Can I control the location of .NET user settings to avoid losing settings on application upgrade?
Asked Answered
R

4

107

I'm trying to customize the location of the user.config file. Currently it's stored with a hash and version number

%AppData%\[CompanyName]\[ExeName]_Url_[some_hash]\[Version]\

I want to it be agnostic to the version of the application

%AppData%\[CompanyName]\[ProductName]\

Can this be done and how? What are the implications? Will the user lose their settings from the previous version after upgrading?

Relict answered 7/3, 2009 at 3:50 Comment(4)
While uzbones's answer is informative with regards to the file location, I believe that Ian's is more correct with regards to upgrading.Inclusion
@AnthonyMastrean i personally think that any important settings should not rely on the ApplicationSettings infrastructure provided my Microsoft. Muxa should just store settings in %AppData%\[CompanyName]/[ProductName] where we can trust it will remain.Leonor
No doubt, my continued experience with the built-in application and user settings has been terrible. I recommend json files in appdata or programdata.Inclusion
You can also store your settings in a registry. See https://mcmap.net/q/57119/-how-to-make-application-settings-independent-of-exe-path for alternative settings class implementation.Eanore
A
41

To answer the first question, you technically can put the file wherever you want, however you will have to code it yourself, as the default place the file goes to is the first of your two examples. (link to how to do it yourself)

As for the second question, it depends on how you deploy the application. If you deploy via a .msi, then there are two hashes in the properties of the setup project (that the msi is built from), the 'upgrade code' and the 'product code'. These determine how the msi can be installed, and if it upgrades, overwrites, or installs beside any other version of the same application.

For instance, if you have two versions of your software and they have different 'upgrade' codes, then to windows they are completely different pieces of software regardless of what the name is. However if the 'upgrade' code is the same, but the 'product' code is different then when you try to install the 2nd msi it will ask you if you want to upgrade, at which time it is supposed to copy the values from the old config to a new config. If both values are the same, and the version number didn't change then the new config will be in the same location as the old config, and it won't have to do anything. MSDN Documentation

ClickOnce is a little bit different, because its based more off of the ClickOnce version # and URL path, however I have found that as long as you continue to 'Publish' to the same location the new version of the application will continue to use the existing config. (link to how ClickOnce handles updates)

I also know there is a way to manually merge configs during the install of the msi using custom install scripts, but I don't remember the exact steps to do it... (see this link for how to do it with a web.config)

Aubin answered 7/3, 2009 at 4:40 Comment(3)
Isn't the upgrade code the one that's supposed to stay constant, and the product code the one that's supposed to change between releases? blogs.msdn.com/b/pusu/archive/2009/06/10/understanding-msi.aspxFreddyfredek
Doh! you are correct, can't believe I got that one backwards (and it took 2 years to catch it). It was like robo-signing for a while at one point in my past :(Aubin
Does that mean, that only the installing user gets her settings upgraded?Cadmarr
L
84

I wanted to add this quoted text as a reference for when i have this problem in the future. Supposedly you can instruct the ApplicationSettings infrastructure to copy settings from a previous version by calling Upgrade:

Properties.Settings.Value.Upgrade();

From Client Settings FAQ blog post: (archive)

Q: Why is there a version number in the user.config path? If I deploy a new version of my application, won't the user lose all the settings saved by the previous version?

A: There are couple of reasons why the user.config path is version sensitive.

(1) To support side-by-side deployment of different versions of an application (you can do this with Clickonce, for example). It is possible for different version of the application to have different settings saved out.

(2) When you upgrade an application, the settings class may have been altered and may not be compatible with what's saved out, which can lead to problems.

However, we have made it easy to upgrade settings from a previous version of the application to the latest. Simply call ApplicationSettingsBase.Upgrade() and it will retrieve settings from the previous version that match the current version of the class and store them out in the current version's user.config file. You also have the option of overriding this behavior either in your settings class or in your provider implementation.

Q: Okay, but how do I know when to call Upgrade?

A: Good question. In Clickonce, when you install a new version of your application, ApplicationSettingsBase will detect it and automatically upgrade settings for you at the point settings are loaded. In non-Clickonce cases, there is no automatic upgrade - you have to call Upgrade yourself. Here is one idea for determining when to call Upgrade:

Have a boolean setting called CallUpgrade and give it a default value of true. When your app starts up, you can do something like:

if (Properties.Settings.Value.CallUpgrade)
{
   Properties.Settings.Value.Upgrade();
   Properties.Settings.Value.CallUpgrade = false;    
}

This will ensure that Upgrade() is called only the first time the application runs after a new version is deployed.

i don't believe for a second that it could actually work - there's no way Microsoft would provide this ability, but the method is there just the same.

Leonor answered 18/12, 2009 at 12:50 Comment(9)
THIS TOTALLY WORKS! I used just the simple if(CallUpgrade) { Upgrade(); } statement.Inclusion
@Ian Boyd: I like this idea and I am totally stoked about having a potential solution however I am confused about one thing. I don't have a Properties.Settings.Value I have the Properties.Settings part but am I missing something or is that specific to you?Cerberus
@RefractedPaladin You'll have to hunt around i guess. The blog post (unhelpfully) refers to ApplicationSettingsBase class. Presumably somewhere in Properties.Settings.xxx.xxx you should find it. i think my current WinForms app is Properties.Settings.Default - but i don't remember.Leonor
After adding CallUpgrade in the settings designer the property Properties.Settings.Default.CallUpgrade is visible when coding. Not tested it yet.Cabezon
This works well, but I remind readers that the path of the config up to but excluding the version number must be the same. i.e. see @Amr's answer. e.g. if a new version of the app is launched from a different file path than a previous version, then Upgrade doesn't work.Ation
@RefractedPaladin it's Properties.Settings.Default.Upgrade()Ation
Don't forget to add Properties.Settings.Default.Save(); after changing it to false :-)Gent
But this only functions if the hash doesn't change! Every time I change something in my program the directory changes (cause of new hash) and Settings.Default.Upgrade() is only working in the same directory. I know what Microsoft want, but I want a bypass to force a Directoyname I want!Dover
It works only when you start your different versions of the *.exe files from the same path (file system's location). Try to move your *.exe file to the new location and you are not able to load settings from previous version anymore.Verger
A
41

To answer the first question, you technically can put the file wherever you want, however you will have to code it yourself, as the default place the file goes to is the first of your two examples. (link to how to do it yourself)

As for the second question, it depends on how you deploy the application. If you deploy via a .msi, then there are two hashes in the properties of the setup project (that the msi is built from), the 'upgrade code' and the 'product code'. These determine how the msi can be installed, and if it upgrades, overwrites, or installs beside any other version of the same application.

For instance, if you have two versions of your software and they have different 'upgrade' codes, then to windows they are completely different pieces of software regardless of what the name is. However if the 'upgrade' code is the same, but the 'product' code is different then when you try to install the 2nd msi it will ask you if you want to upgrade, at which time it is supposed to copy the values from the old config to a new config. If both values are the same, and the version number didn't change then the new config will be in the same location as the old config, and it won't have to do anything. MSDN Documentation

ClickOnce is a little bit different, because its based more off of the ClickOnce version # and URL path, however I have found that as long as you continue to 'Publish' to the same location the new version of the application will continue to use the existing config. (link to how ClickOnce handles updates)

I also know there is a way to manually merge configs during the install of the msi using custom install scripts, but I don't remember the exact steps to do it... (see this link for how to do it with a web.config)

Aubin answered 7/3, 2009 at 4:40 Comment(3)
Isn't the upgrade code the one that's supposed to stay constant, and the product code the one that's supposed to change between releases? blogs.msdn.com/b/pusu/archive/2009/06/10/understanding-msi.aspxFreddyfredek
Doh! you are correct, can't believe I got that one backwards (and it took 2 years to catch it). It was like robo-signing for a while at one point in my past :(Aubin
Does that mean, that only the installing user gets her settings upgraded?Cadmarr
V
34

The user.config file is stored at

C:\Documents and Settings>\<username>\[Local Settings\]Application Data\<companyname>\<appdomainname>_<eid>_<hash>\<version>

<C:\Documents and Settings> is the user data directory, either non-roaming (Local Settings above) or roaming.
<username> is the user name.
<companyname> is the CompanyNameAttribute value, if available. Otherwise, ignore this element.
<appdomainname> is the AppDomain.CurrentDomain.FriendlyName. This usually defaults to the .exe name.
<eid> is the URL, StrongName, or Path, based on the evidence available to hash.
<hash> is a SHA1 hash of evidence gathered from the CurrentDomain, in the following order of preference:
1. StrongName
2. URL:
If neither of these is available, use the .exe path.
<version> is the AssemblyInfo's AssemblyVersionAttribute setting.

Full description is here http://msdn.microsoft.com/en-us/library/ms379611.aspx

Ventura answered 7/3, 2009 at 4:18 Comment(0)
N
5

(I'd add this as a comment to @Amr's answer, but I don't have enough rep to do that yet.)

The info in the MSDN article is very clear and appears to still apply. However it fails to mention that the SHA1 hash is written out base 32 encoded, rather than the more typical base 16.

I believe the algorithm being used is implemented in ToBase32StringSuitableForDirName, which can be found here in the Microsoft Reference Source.

Nebulose answered 21/10, 2014 at 18:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.