If I rename my compiled application for example from myapp.exe
to app.exe
then when I run the renamed executable a new user settings folder is generated in this path:
C:\Users\{User}\AppData\Local\{CompanyName}\{ExecutableName}_Url_{SystemGUID or something strange}
So I loose all the saved settings.
Then how I could solve this problem defining in a VBNET
WinForms
my own location to store the user.config
file, or any other solution using the applicationsettings infrastructure ? (not saving the settings on the registry or other things)
PS: I've read this SO post which is a little bit different question but anyways I didn't understood the supposed solution Can I control the location of .NET user settings to avoid losing settings on application upgrade?
More info and a tidbit from the link which answers your question:
The "systemGUID or something" you reference is actually a hash of 2 things (Reference MSDN My.Settings):
<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:
- StrongName
- URL If neither of these is available, use the .exe path.
Without a StrongName, your location is varying by path which is the problem you describe. Since BOTH eid and hash will use StrongName for the hash(es), the full path should remain the same even if they move it somewhere else or install a new version. When using a StrongName the credentials come from the app and the hashes don't change and the method of last resort (the exe path) is never used. Which answers your basic question: use a Strong Name and the path wont change.
New releases/versions will create a sub folder tree under that folder for each version for Settings. The Upgrade
method for Settings
mentioned in the link (apparently) facilitates importing Settings from the/a previous version. A change in the EXE Name will cause the AppDomain.FriendlyName (3rd element) to change though.
Isolated Storage is another option, and it is not as hard as it first looks, but has similar behavior. With Iso, you dont specify a folder as it just creates one in an obscure location like Users\<User>\Isolated Storage\zhxytg\dhfyres\
. The location CAN remain the same for all versions of the app, even if you rename it, if you use ClickOnce (so, this is another viable solution).
I think you have to use ClickOnce (StrongName as a replacement doesnt come up in MSDN) to get Application level evidence. As a side benefit, with ISO, even under the highest security a non admin user can read/write to shared files in ProgramData\AllUsers
(as might be the case for a licence, or shared settings for an app suite) at least with W7. The app's hash permits it to write to that path, so it can do some things we normally can't do.
If you dont use ClickOnce, you can still get a stable folder per install and read/write to AllUsers
. A new install (to a different folder) will result in a different hash and file location; same with changing the filename. Even if you managed to store the old location somewhere, a new install probably would not have rights to the old file (havent tried).
ISO removes varying by EXEName, but it does not use My.Settings. Instead you use IsolatedFileStreams
created by IsolatedStorageFile
objects. And you'd have to take over organizing and managing the values and names of the various Settings. The type of Isolated Storage used (App / User) depends on the credentials available.
Isolated storage has its place, but seems to be overkill for Settings.
You mentioned that you usually only use MySettings for trivial apps. As such, a StrongName simply to stabilize the path for Settings seems to be overkill. ISO is very interesting, but there is something much simpler. This third option falls into the or other things
you didn't want, but is very flexible.
Build your own Settings Class around Serialization. For simple settings, these likely arent much more than a set of Name-Value Pairs {LastPath = "....."; FormLeft = x; FormTop = y ...}. Save these in a Dictionary(Of String, String)
or Dictionary(Of enumSettings, String)
and just serialize (save) the entire container:
Dim bf As New BinaryFormatter
Using fs As New FileStream(myFile, FileMode.OpenOrCreate)
bf.Serialize(fs, _UserOpts)
End Using
Getting the values back is just as simple. For more complex projects where there are many Types to save like Integer, Date, Array, ArrayList, List(of T) and so forth , create a UserOptions Class for them and serialize that instead.
Note that you pass a filestream to the serializers, so you have full control over the name and location, such as C:\Users\<username>\AppData\Local\<Company>\<Product>\Settings.bin
The location wont change by version, culture, assembly etc. It will stay where you put it.
This does run out of steam when you try to serilize Types like Point, Size and Font because Objects cannot be serialized directly. Especially, with ProtoBuff there are multiple options to convert these to something serializable on the fly or beforehand.
I suppose you could also open your config file from specific location using ConfigurationManager.OpenExeConfiguration method.
Hope I helped!