Wednesday, March 30, 2011

Where do I put my data to keep it safe from ClickOnce updates?

Sometimes you want to include a file with your ClickOnce application and then update it using input from your customer. Or about your customer. Or about what your customer is doing with your application. (“You say you didn’t hit the delete button, but according to the log file, you hit it exactly 47 minutes ago.”)

To include the file in your deployment, add it to your project, and set the properties correctly. “Build Action” should be set to “Content”, and “Copy to Output Directory” to “Copy Always”.
When you deploy a file with a ClickOnce application, it is kept with the installed files. When you deploy a new version of the same application, it creates a new folder for the new version, and installs the files there, and you lose access to the original file, which defeats the whole purpose of saving the user’s changes to it. So if you don’t want to lose the file when there is an update, you need to move it out of the deployment folder.

If you are running Windows Vista or Windows 7, there are very few places to which you can write data on the user’s computer (Cancel or Allow?). You could put it in MyDocuments, but the user is likely to stumble over it and hurt his toe and sue you, or he may delete it because he doesn’t know what it is. So to store data used by your application, the recommended location is Local Application Data.
Create a folder in LocalApplicationData using your company name or product name. You could use another company’s name (like, say, ‘Microsoft’), but this might lead to unpleasant surprises down the road. You could also call it George, but you’ll forget that and then spend an hour looking through all the folders trying to find your file.

The first time the user runs the application, you want to create your folder and copy the file over there. When the user runs it the next time, you don’t want to copy the file over there. If you did that, it would be exactly what ClickOnce does, and would defeat the purpose of this entire blog post.
So the most effective thing to do is check for the directory. If it’s not there, create it. Then check for the file in the directory, and if the file’s not there, copy it over. You could assume if the directory is there, the file will be, but if your application mysteriously crashes (like the user’s laptop gets run over by a truck at that exact moment of execution), then the file could be missing. It only costs you one line of code to protect yourself from an embarrassing execution error.

I’ve tried to make this narrow enough to actually fit in my blog. Ordinarily, I wouldn’t use all the extra variables. I’m posting this in both C# and VB because I’m a C# developer trapped in a VB developer’s body.

Read more: RobinDotNet's Blog