Published a ClickOnce application and it keeps resetting its settings

If you have user-level settings, ClickOnce should copy them forward to the next version's cache when the user gets an update. There are a couple of cases where it doesn't copy the files forward, such as when you change the certificate.

Application-level settings are not retained and carried forward to the next version.

I don't recommend using this mechanism and relying on it. You might want to check out this article about keeping your data safe from ClickOnce updates. We rolled our own configuration manager, and store the data as XML and store it as noted in that article. This way, you control what happens to the data.

The only drawback is that when the user uninstalls the app, it leaves this data behind. On the other hand, when the user uninstalls the app, it leaves his data behind, so if he is uninstalling it because he's having a problem, or he clears his ClickOnce cache because he has his problem, then when he installs a new version, his data is still there.


I figured a solution that may help future developers with this issue. I realized that, for some reason, the updated version reads some previous configuration settings, but not the last one. For example, if you have this app folders:

myapp_0000000000000000_0001.0000_a4e7e981ca9c18fa
myapp_0000000000000000_0001.0000_a4e7e981ca9c19ee
myapp_0000000000000000_0001.0000_a4e7e981ca9c20aa

when you update, the configuration settings are copied from some random folder different than the last one (I don't know if this is random, probably will take the oldest, but I'm not sure).

So, if you delete the other folders, and left only the last version one, when you update there's no other choice than take the config settings from this only one folder. Try it out for yourself.

So I made this code snippet that runs every time the app starts, that removes the old version folders, so when the next updates came, everything will work fine.

private void ClearOldConfigurations()
{
    var level = ConfigurationUserLevel.PerUserRoamingAndLocal;
    var configuration = ConfigurationManager.OpenExeConfiguration(level);
    var configurationFilePath = configuration.FilePath;

    var routePieces = configurationFilePath.Split(Path.DirectorySeparatorChar);

    var toRetainFolder = string.Empty;
    var toClearFolder = string.Empty;
    for (int i = routePieces.Length - 1; i > 1; i--)
    {
        if (routePieces[i].ToLower() == "data")
        {
            toRetainFolder = string.Join(Path.DirectorySeparatorChar.ToString(), routePieces.Take(i));
            toClearFolder = string.Join(Path.DirectorySeparatorChar.ToString(), routePieces.Take(i - 1));
            break;
        }
    }

    if (string.IsNullOrWhiteSpace(toRetainFolder) || string.IsNullOrWhiteSpace(toClearFolder))
    {
        return;
    }

    foreach (var dir in Directory.GetDirectories(toClearFolder))
    {
        if (dir.ToLower().Trim() != toRetainFolder.ToLower().Trim())
        {
            try
            {
                Directory.Delete(dir, true);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }
}

Probably not the cleanest solution, but worked for me.


For anyone who runs into this problem: Check if you have an unconditional

Properties.Settings.Default.Upgrade();

in your code. In a ClickOnce installation with multiple versions, this statement copies the user settings from a previous version and overwrites any settings that were saved in the last session. The correct pattern is:

if (Properties.Settings.Default.UpgradeRequired)
{
    Properties.Settings.Default.Upgrade();
    Properties.Settings.Default.UpgradeRequired = false;
    Properties.Settings.Default.Save();
}

where UpgradeRequired is a setting that defaults to true.


It is your job to upgrade the previous settings when you update your application.

Settings.Default.GetPreviousVersion() and Settings.Default.Upgrade() can be helpful for this.