I've updated one of my WPF apps from .NET Framework 4.7 to .NET 5. It uses the ClickOnce Installer to install updates. Since the change to .NET 5, I'm using the AssemblyVersion for setting the version instead of rely on the ClickOnce version, but the ClickOnce ApplicationVersion is also set.
Additionally I'm using application settings (user.config file) to store some user settings. Since the update to .NET 5, the user settings are always deleted after an update. I tought it is because of the different AssemblyVersion, but as far as I understand this site, the config file sould be merged by ClickOnce automatically.
Also a Settings.Default.Upgrade() didn't change anything. The user.config is still not existing for the updated version and therefore, no settings could be loaded from previous verions.
Did I understand something wrong? Should it work or do I have to change anything?
Thank you in advance for your help :)
I have had the same issue. Signing the assembly of the WPF project did the trick for me and fixed the problem.
Project properties -> Singing -> "Sign the assembly"
Create a strong name key file
Putting this in the main form loaded event worked for me:
if (Properties.Settings.Default.UpgradeRequired)
{
Properties.Settings.Default.Upgrade();
Properties.Settings.Default.UpgradeRequired = false;
Properties.Settings.Default.Save();
}
Set a Setting in settings called UpgradeRequired to true
This way every time the program gets updated, the Upgrade method gets called and settings get carried forward to the next version.
Related
I've updated one of my WPF apps from .NET Framework 4.7 to .NET 5. It uses the ClickOnce Installer to install updates. Since the change to .NET 5, I'm using the AssemblyVersion for setting the version instead of rely on the ClickOnce version, but the ClickOnce ApplicationVersion is also set.
Additionally I'm using application settings (user.config file) to store some user settings. Since the update to .NET 5, the user settings are always deleted after an update. I tought it is because of the different AssemblyVersion, but as far as I understand this site, the config file sould be merged by ClickOnce automatically.
Also a Settings.Default.Upgrade() didn't change anything. The user.config is still not existing for the updated version and therefore, no settings could be loaded from previous verions.
Did I understand something wrong? Should it work or do I have to change anything?
Thank you in advance for your help :)
I have had the same issue. Signing the assembly of the WPF project did the trick for me and fixed the problem.
Project properties -> Singing -> "Sign the assembly"
Create a strong name key file
Putting this in the main form loaded event worked for me:
if (Properties.Settings.Default.UpgradeRequired)
{
Properties.Settings.Default.Upgrade();
Properties.Settings.Default.UpgradeRequired = false;
Properties.Settings.Default.Save();
}
Set a Setting in settings called UpgradeRequired to true
This way every time the program gets updated, the Upgrade method gets called and settings get carried forward to the next version.
Background
I have a simple WinForms application written in C#. I debated deployment solutions for a while but ultimately decided to abandon ClickOnce as a few of the constraints were crucially restrictive.
Instead, I've adapted a simple solution of versioning the application via the assembly/file versions (I keep them in sync) in the application's properties. I'm deploying via a Setup Project (*.msi). I store the latest assembly version number in an XML file online, as well as the latest installer file. At run-time, I simply check the Application.ProductVersion against the latest version online and open an update dialog if an update is available.
Problem
This has worked pretty well thus far, but I've recently noticed a major problem with this approach. When the assembly version of the application is updated, a new version of the user's settings file (user.config) is created in AppData/Company/Product/Version/blahblahblah. This obviously forces the user to reset everything in the new version.
Suggested Solutions
I'm not sure how to proceed. The application only has 1 release thus far and the current user base is basically whoever I can beg to test it, so switching up strategies is no big deal. I've considered:
1.) Write my own settings system and thus have complete control over where/how the settings file is stored and used.
2.) Re-think my versioning/update strategy so that the update is not based on the assembly version. I'm not sure how I would do this, but my testing seemed to reveal that even building and installing a new version with the same assembly version would still break user.config.
I guess what I'm truly asking if there is any way to preserve the default settings system since it's so easy to use while also adapting it to my deployment strategy.
Use the built in Settings classes, you just need to upgrade the settings anytime you change the application version. Here's how to do it:
In the Settings.settings file, create a new setting
UpdateSettings type=bool Scope=User Value=True
Include the following code before you use any Settings (it can run every time the app runs, as this makes running in debugger easier too)
// Copy user settings from previous application version if necessary
if (MyApp.Properties.Settings.Default.UpdateSettings)
{
MyApp.Properties.Settings.Default.Upgrade();
MyApp.Properties.Settings.Default.UpdateSettings = false;
MyApp.Properties.Settings.Default.Save();
}
When your new application version is run UpdateSettings will have a default value of True and none of your old settings will be used. If UpdateSettings is true we upgrade the settings from the old settings and save then under the new app version.
Here's how I solved it.
In the GUI application it is very easy to restore the settings by executing
Properties.Settings.Default.Upgrade();
Properties.Settings.Default.Reload();
Properties.Settings.Default.Save();
However, I've always had the problem that all other libraries lost their settings when a new version has been installed. With the following implementation the software runs through all assemblies of the AppDomain and restores the settings of the respective library:
foreach(var _Assembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach(var _Type in _Assembly.GetTypes())
{
if(_Type.Name == "Settings" && typeof(SettingsBase).IsAssignableFrom(_Type))
{
var settings = (ApplicationSettingsBase)_Type.GetProperty("Default").GetValue(null, null);
if(settings != null)
{
settings.Upgrade();
settings.Reload();
settings.Save();
}
}
}
}
I've implemented the code in the App.xaml.cs of the GUI project and it will always be executed when the setting "NewVersionInstalled" was set to true by a new version.
Hope this helps!
I prefer this alternative which does not need the additional setting Settings.Default.UpdateSettings
string configPath = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal).FilePath;
if (!File.Exists(configPath))
{
//Existing user config does not exist, so load settings from previous assembly
Settings.Default.Upgrade();
Settings.Default.Reload();
Settings.Default.Save();
}
I want my WPF application publish version. I tried using the answer for this question. It works but the problem is we can manually change the values there. I want to know how many times my project was actually published (don't need version number. Just how many times did I publish my application). Can this be done?
Using Click Once, each time you publish, Visual Studio will change the number automatically. It will increment the value each time you publish. Your problem is that you have manually changed the number. The solution is to publish and just let Visual Studio update the value... you should notice that your project needs to be saved once you have published. This is because Visual Studio just incremented the value for you.
UPDATE >>>
If you want to access the published version from code (which you should have made clear in your question), then you can use this code, but you have to ensure that the application is network deployed first... that means that it has actually been published, so it won't work while you are debugging. Try this:
private string GetPublishedVersion()
{
if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed)
{
return System.Deployment.Application.ApplicationDeployment.CurrentDeployment.
CurrentVersion.ToString();
}
return "Not network deployed";
}
You may be confused by 2 sets of numbers. Please note that you can set version of your WPF app in TWO different places:
Project Properties / Publish tab / Publish Version
AssemblyVersion declared in AssemblyInfo.cs file, which you can find if you expand Project Properties node in Solution Explorer.
They are similar in the sense that they both provides 4 numbers: major, minor, build and revision. The difference is that Publish Version is only available if the app was actually Published (i.e. Installed). It is not available in your debug session nor if you just copy the executable to another machine and run it there. SO, if you just need to track version of your EXE file, use AssemblyInfo.cs.
Correspondingly, to read the data use the following code:
1 To read Publish version (declared in Publish tab)
using System.Deployment.Application;
ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString();
Note that in this case: a) you need to add reference to System.Deployment assembly, b) if the app was not deployed, it won't work.
2 To read Assembly Version (declared in AssemblyInfo.cs)
Assembly.GetExecutingAssembly().GetName().Version;
This one always works.
Universal solution if we get application version from not startup assembly:
var version = System.Reflection.Assembly.GetEntryAssembly().GetName().Version;
string appVersion = $"{version.Major}.{version.Minor}";
GetEntryAssembly give version of startup project.
var obj=Assembly.GetExecutingAssembly().GetName().Version;
string version= string.Format("Application Version {0}.{1}", obj.Build, obj.Revision);
OR
string version= string.Format("Application Version {0}.{1}", obj.Major, obj.Minor);
whichever properties suits you.
This is an issue that only happens for some users. Whenever I release a new version of my app in Marketplace I get emails from users saying that all the settings in the app are lost.
I can't reproduce this myself and I have no code that can wipe the IsolatedStorage.
Would be great if anyone out there had a clue on what might be causing this.
Update: Not sure if the following applies to WP7 apps - I'll leave it here just in case. I have only tried this for normal apps.
You will need to "upgrade" the old settings file.
You also need to know when you need to do this (i.e. only when a new version is installed).
To know when you need to upgrade settings, add a boolean called (say) NeedSettingsUpgrade to your settings, and default it to true.
Then call the following function somewhere near the start of Main():
/// <summary>Upgrades the application settings, if required.</summary>
private static void upgradeApplicationSettingsIfNecessary()
{
// Application settings are stored in a subfolder named after the full #.#.#.# version number of the program. This means that when a new version of the program is installed, the old settings will not be available.
// Fortunately, there's a method called Upgrade() that you can call to upgrade the settings from the old to the new folder.
// We control when to do this by having a boolean setting called 'NeedSettingsUpgrade' which is defaulted to true. Therefore, the first time a new version of this program is run, it will have its default value of true.
// This will cause the code below to call "Upgrade()" which copies the old settings to the new.
// It then sets "NeedSettingsUpgrade" to false so the upgrade won't be done the next time.
if (Settings.Default.NeedSettingsUpgrade)
{
Settings.Default.Upgrade();
Settings.Default.NeedSettingsUpgrade = false;
}
}
Note: You will of course need to call Settings.Default.Save() before your program exits, otherwise the settings change won't be persisted.
My approach to this has been to use the assembly version number as the trigger for the upgrade. On first run it save settings in the format required for v1.0 and the assembly version number 1.0.0.0. When an upgrade occurs it compares the saved setting number (1.0.0.0) with the upgraded assembly number 1.1.0.0 and decides that an upgrade is needed.
I discovered that doing a redeploy for visual studio did not guarentee to do an upgrade, sometimes it did an uninstall, reinstall which was not as good. So I changed to using Windows Phone Powertools to test my "upgrade" path as it seems to reliably do upgrades.
When debugging my project in Visual Studio 2008, my Settings.settings file keeps getting reset between builds. Is there a way to prevent this from happening?
Thanks.
Okay, I found out the answer I was really looking for. Basically, you need to call LocalFileSettingsProvider.Upgrade. However, since I will be deploying using ClickOnce, it will do it for you automatically.
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.
REF: http://blogs.msdn.com/rprabhu/articles/433979.aspx
I believe Settings.settings files are saved based on the current version number, basically as a "feature" where settings are not saved between differing versions of the same program on a machine. Assuming you're incrementing the version number automatically when compiling (1.0.* in AssemblyInfo.cs), you'll be resetting your settings everytime you compile a new version.
To correct this, the best course would be to serialize your own settings file to the Application Data directory.
Off the top of my head I think you can set in the properties of the file (in Visual Studio right click, Properties) an option to "do not copy" when the project is built/run. What is happening probably is when your project is built, the settings file is copied to the debug bin directory, overwriting the settings file from the previous run.
Amongst other reasons, the Settings file keeps getting reset each time you Debug simply because the next time you Debug, you'll be able to test the whole application all over again. Not resetting the Settings may lead to undetected bugs.