.NET Resources, Settings and user.config Upgrade

I mainly write .NET 2.0 winform/desktop applications and have been using the Visual Studio Resources and Settings "strongly typed" mechanism. I have found this feature, that effectively comes free with Visual Studio, to be fantastic.
The Resources mechanism allows me to very simply create Resources of various types and know that they do indeed exist at compile time, unlike .NET 1.0/1.1, where I could easily create entries but I could easily use the key wrong into the ResourceManager and not realise this until I got an empty string or similar at runtime when I was expecting a value of some sort.
The Settings mechanism is also very similar and allows me to specify whether the setting is application or user oriented. Generally I find most of my entries are user oriented as I mainly use Settings to store application options, such as those entries you might find in the Options dialog box and the location and state of the application window when it was closed.
This was all going really well, but each time I released a new version all the Settings would revert back to their original default settings. I needed to find a way to upgrade an application in such as way that the user settings would be kept from a previous version of the software.
Changes to the defalt settings are stored in a file called user.config in a location below the users "Documents and Settings" (XP) or AppData (Vista) …\Company Name\Application Name\Version, e.g. [user]\MyCompany\MyApplication\ The next release of the software reads/writes the user.config to a different version folder, e.g. [user]\MyCompany\MyApplication\
I did the usual Google and found a few similar articles talking about ApplicationBase.Upgrade(), although it took me about two hours to actually get it to work!! and as it turned out I did it right within the first 10 minutes but thought it wasn’t working. So to save you all the hassle here is what I did. Now it may be that my problems stemmed from the fact I was using Vista, but the same issue that caught me out may also be true of XP.
In the main() method of my winform application (before calling Application.Run) I wrote (C#) code like this:

if (MyDefaultNamespace.Properties.Settings.Default.Application_UpgradeRequired)








    catch (Exception exception)


        // Squash and continue without performing the upgrade




        /* Whether we succeed or fail flag upgrade as done.

         * We don’t want to try again next time even if we failed
         * as once the app has been run up once the user may have made
         * manual changes and we don’t want to oberwrite them.


Settings.Default.Application_UpgradeRequired = false;


You can see from the above code that all the work is really done in the MyDefaultNamespace.Properties.Settings.Default.Upgrade() but what happens when you call this?
Essentially, it somehow knows what the last version was (don’t know exactly how it knows, but I guess it is based on examining the sibling version folders and deducing the previous version). If there is not previous version then nothing happens. If there is a previous version but no user.config is found (or something is wrong with it) then it raises an exception. But given it finds a previous version, any entries in the previous version that still exist in the new version are carried forward, any that do not are ignored. It seems you can use "NoSettingsVersionUpgradeAttribute" on the Settings wrapper class to prevent it being upgradeable, so you could split you Settings into two (or more) resource files, one that is Upgradable and one that is not.
You can use MyDefaultNamespace.Properties.Setting.Default.GetPreviousVersion("MySetting") to retrieve a value of a specific previous setting, which can be useful if either you only want to upgrade a few select items, or perhaps you changed the name of a setting in the latest release and want to bring forward th value from the previous version when it was called something else.
The issue I fell foul of was that despite there being a previous version, calling Upgrade() didn’t seem to do anything. On examination I found that my original version had gone into a folder something like this:
but the new version had gone to:
I figured that because the version folders were not siblings that was why it didn’t work – which as it turns out was right, but why was the application creating a different application folder? I tried running the application in Visual Studio in both Debug and Release mode but got the same results, then as a final test I updated my installer with the new application and installed it, and then it worked! Yes, once installed the version folder appeared below the original "MyApplication.exe_Url_hwk1afgxmxf35sa0voi4agxgxtjhgmdn" folder…grrrrr.
I think maybe the reason there being a different application folder was down to Vista security stuff, as XP doesn’t seem to create such weird application folder names, so maybe this is just a "Vista Developer Beware" issue.
As an aside, and to explain a little of the other code above. I create a new Setting in my application called "Application_UpgradeRequired" as a boolean and set it to true. I then used this to determine whether I had tried to upgrade before, as the first time I upgrade I set this to false to prevent it upgrading again. I just squash any errors that might have occured, but you could offer MessageBoxes or whatever to ask "Do you want to try again next time" or to ask whether the user wants to migrate previous setting in the first place.
So, if you find it is not working during your development/unit testing don’t worry it is Visual Studio and/or Vista messing with you…all will be well once installed and tested as a real application.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: