Reputation: 105067
So, long story short, I'm developing an application that will make use of some configuration info that may be changed at runtime through the application itself. For the purpose I've thought of using the Settings
class.
The problem, thought, is that information is not persisted between different runs of the application:
Run 1)
Console.WriteLine(Settings.Default["User"]); //prints "Default user"
Settings.Default["User"] = "abc";
Console.WriteLine(Settings.Default["User"]); //prints "abc"
Run 2)
Console.WriteLine(Settings.Default["User"]); //prints "Default user"
Settings.Default["User"] = "abc";
Console.WriteLine(Settings.Default["User"]); //prints "abc"
(both print exactly the same output)
Both runs show up the same first print "Default user", although on the 2nd run I'd like to get "abc", indicating that the info is not being persisted between different application executions.
I acknowledge this must be related with the way Visual Studio handles .config files, but even so I'd like to know how to correct for this (nasty) behavior?
Upvotes: 8
Views: 3101
Reputation: 12654
By default, App.config is not copied directly, rather it's content is placed in <assembly-name>.config
file in output folder. Copy settings do not apply to this operation.
Generally, it is not a good practice for application to change its own app.config. If you are developing application that may be used by several users on the same PC, then use Settings instead. That way each user can have his own settings.
For services and system-wide settings, consider using another storage, like a separate config file, registry or database.
Edit about saving Settings:
When using settings class, you should call Save() to write it to the file, otherwise changes in settings will be discarded when application is closed. If you often terminate your application during development, and it does not reach it's end code(where you would normally place a call to Save()), then you have several options:
Settings.Default.Save()
in watch window and refresh it every time you want to save.Upvotes: 7
Reputation: 5831
Maybe you can use the filesystem to create a symbolic link between the 2 files so that it actually edits the file in the source. However I can't think of a quick solution for the compiler to not overwrite the configuration file (and thereby removing the link).
At least this approach does not require you to code a workaround. It also does not influence the way you want to save the settings (like changing from default to user scope). So it is only effective when developing.
Upvotes: -1
Reputation: 147
The following is what I used to save something back to the app.config file.
//write the last run time to config
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
if (config.AppSettings.Settings["LastRunTime"] == null)
{
config.AppSettings.Settings.Add("LastRunTime", DateTime.UtcNow.ToString());
}
else
{
config.AppSettings.Settings["LastRunTime"].Value = DateTime.UtcNow.ToString();
}
config.Save();
Hope this helps.
Upvotes: 2
Reputation: 132
I'm not sure how this is different from your approach, but I solved this problem using the Settings file.
First, create the Settings file from the Properties menu of your project. Right Click on the project in the Solution Explorer, and Select "Properties". Go to the Settings Tab and create the settings file. Once the file is created, you should see a datagrid where you can enter a Name/Type/Scope/Value. Set up all the variables you want to use here (I'm not sure if you can create more variables at run time, but I don't think so).
Now, in code, you can use the Properties class which will be in the default namespace of your project.
To read a setting:
Properties.Settings.Default.SrcDir;
and to save a setting:
Properties.Settings.Default.SrcDir = src;
Properties.Settings.Default.Save();
Upvotes: 1
Reputation: 65554
This code with the User property set with User
scope:
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(ConsoleApplication4.Settings1.Default["User"]); //prints "DefaultUser"
ConsoleApplication4.Settings1.Default["User"] = "abc";
Console.WriteLine(ConsoleApplication4.Settings1.Default["User"]);
ConsoleApplication4.Settings1.Default.Save();
Console.Read();
}
}
}
Saves the setting to a obscure location:
C:\Users\username\AppData\Local\ConsoleApplication4\ConsoleApplication4.exe_Url_acauylh2btl2j4ed0ilz0mujq5aomfmu\1.0.0.0
So even in your app.config you still see "Default User" after running the application multiple times:
<userSettings>
<ConsoleApplication4.Settings1>
<setting name="User" serializeAs="String">
<value>Default User</value>
</setting>
</ConsoleApplication4.Settings1>
</userSettings>
In the User.Config it will be the last set value for the User.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<userSettings>
<ConsoleApplication4.Settings1>
<setting name="User" serializeAs="String">
<value>abc</value>
</setting>
</ConsoleApplication4.Settings1>
</userSettings>
</configuration>
When I run this code the first time the output is "Default User", "abc", the second run the output is "abc" "abc"
Perhaps it was just the Save();
that you were missing.
If your App.Config file is stored with the program under Program Files somewhere, a normal user (non-admin, non-power user) will NOT be able to write to that file.
You would have to write a exe or script that you fire from a PreBuild event that writes the User.Config Settings back to the settings1.settings file and in turn built into the App.Config.
I dont think you want to do this, because User.config overrides App.Config and the second time you debug the code you will get "abc" "abc".
I am quitely confident it was just the Save()
that was missing. Or that Application scope settings are supposed to be Read-Only.
Upvotes: 2