Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Renaming User Settings Properties between Software Versions

5.00/5 (6 votes)
30 Aug 2011CPOL4 min read 17.9K  
How to migrate User Settings properties between software versions after you've renamed them

Introduction

In this article, I will show you how to migrate user settings that have been renamed between versions of your software.

Background

In general, user settings don’t get changed, and it is a best practice to create a wrapper class that hides the low level access to the user settings; this allows you to rename the class properties without having to change the actual user setting property name.

As you can see in this simple class example, the property UserString actually points to a user setting property called OldUserValue, so if you want to rename the property UserString, it doesn’t affect the lower level code of where the property is actually stored.

C#
public static class UserSettings
{
    public static string UserString
    {
        get { return Properties.Settings.Default.OldUserValue; }
        set { Properties.Settings.Default.OldUserValue = value; }
    }

    public static void LoadUserSettings()
    {
        if (Properties.Settings.Default.DoUpgrade)
        {
            Properties.Settings.Default.Upgrade();
            Properties.Settings.Default.Reload();
            Properties.Settings.Default.DoUpgrade = false;
            SaveUserSettings();
        }
    }

    public static void SaveUserSettings()
    {
        Properties.Settings.Default.Save();
    }
}

You will also notice in the above class that in the LoadUserSettings() method, it checks the DoUpgrade property (which has a default value of true) to see if this is the first time this version of the software has been executed; if so, it will use the standard .NET routines to migrate the user settings from any previously installed version of the software.

Using the Code

Now let us just consider the possibility that you want to rename the actual user setting property. This is simple enough to do, just go to the settings designer and you type a new name for your property, and VS is good enough to find all the places you’ve used this property in your code and rename it for you.

However, when you run this new version of your code, it doesn’t migrate your old settings, basically because it doesn’t keep track of what user settings properties were called in previous versions, and neither should it.

Then, you find a method called GetPreviousVersion(), which when you read its description sounds great, you can use this to find old user setting properties and manually migrate them to their new names. So you add code into your LoadUserSettings() to migrate the changes. As you can see, we’ve renamed the property OldUserValue to NewUserValue.

C#
public static class UserSettings
{
    public static string UserString
    {
        get { return Properties.Settings.Default.NewUserValue; }
        set { Properties.Settings.Default.NewUserValue = value; }
    }

    public static void LoadUserSettings()
    {
        if (Properties.Settings.Default.Upgrade)
        {
            Properties.Settings.Default.Upgrade();
            Properties.Settings.Default.Reload();
            Properties.Settings.Default.Upgrade = false;

            try
            {
                object oldValue = 
                  Properties.Settings.Default.GetPreviousVersion("OldUserValue");
                if (oldValue != null && oldValue is string)
                    UserSettings.UserString = (string)oldValue;
            }
            catch { }

            SaveUserSettings();
        }
    }

    public static void SaveUserSettings()
    {
        Properties.Settings.Default.Save();
    }
}

But something’s is not working; every time GetPreviousVersion() is called, an error is thrown: SettingsPropertyNotFoundException. After double checking everything, you know that is what you called the property in the old version, and you even check the user.config file that was left over from the previous version and you can see the property exists, so why can’t GetPreviousVersion() find it?

Well, it turns out that GetPreviousVersion() first looks at your current user settings properties; if it can’t find the property name there, it throws this error. I don’t quite understand the logic behind this but let’s assume that it’s been done this way for a logical reason. So how do you get around that? You could go back to the settings designer and add the property back so GetPreviousVersion will work, but that leaves your code open for errors. You might accidentally reference the wrong property somewhere and spend hours tracking down a bug due to a simple typo.

Fortunately, there is a way to add old properties so that GetPreviousVersion will find the old setting, and also stop you accidentally using this property in your code. All we have to do is extend the existing Settings class with our obsolete properties. You will find the existing class in the Settings.Designer.cs file, but don’t add your code in there as this file is auto-generated so it will be lost if you ever make changes in the settings designer.

C#
namespace UserSettings.Properties
{
    internal sealed partial class Settings : ApplicationSettingsBase
    {
        [UserScopedSettingAttribute]
        [DebuggerNonUserCodeAttribute]
        [DefaultSettingValueAttribute("")]
        [Obsolete("Please use NewUserValue instead")]
        [NoSettingsVersionUpgrade]
        public string OldUserValue
        {
            get { throw new NotSupportedException("OldUserValue is obsolete"); }
            set { throw new NotSupportedException("OldUserValue is obsolete"); }
        }
    }
}

The three most important parts of adding the obsolete property are:

  1. You need to ensure it’s in the same namespace as your other settings, you can find this by looking in the file Settings.Designer.cs.
  2. It needs to be marked with the Obsolete attribute, add a good reason as to why this property is now obsolete.
  3. You need to add the attribute NoSettingsVersionUpgrade so the method Upgrade will not try and transfer the value as this will cause the set method to throw an error.

Once this code has been added, the GetPreviousVersion method will now work, you can retrieve the old value and store it in the new user setting property.

Points of Interest

Also, if you accidentally try and use the old property in your code, the compiler is nice enough to warn you with a nice message.

renamingusersettings/RenameUserSettings.jpg

Credit

I would like to give some of the credit for this solution to Tim Armstrong, who wrote a blog article back in 2008 (Tim Armstrong's blog). It took me three days of trial and error and searching the net to find the solution.

History

  • 2011-08-30 - v1.0 - Article added

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)