Persisting the data in app.config between debugging sessions
Asked Answered
B

5

8

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?

Brightwork answered 23/3, 2013 at 3:57 Comment(1)
Did you try calling Save on the settings (from MS). Or for more 'elaborate' efforts, you can do ConfigurationManager.OpenExeConfiguration (or OpenMappedExeConfiguration) - then Save, SaveAs (e.g. this )Bewhiskered
M
7

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:

  1. Use debugger watch window to call Save(). To do that, place an expression like Settings.Default.Save() in watch window and refresh it every time you want to save.
  2. You can try using a timer to call Save every second.
  3. You can insert Save() calls in your code after settings change.
  4. You can write custom Settings provider or wrapper that will immediately save settings after every change.
Meetly answered 24/3, 2013 at 8:51 Comment(1)
My application won't be used by several users. I just want a quick way to load / store specific data in my application. From what I've read, the Settings class was created just for that purpose (and I believe that's also the reason they let you define settings through the Settings class). So my original question stands still : when developing, how to avoid losing the data I'm saving in the files between execution runs?Brightwork
E
2

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.

Persisting the data in app.config between debugging sessions

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.

Exserviceman answered 31/3, 2013 at 4:16 Comment(1)
Sorry about that, perhaps it was just the Save(); that you were missing. Or that Application scope are supposed to be Read-Only.Exserviceman
W
2

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.

Winniewinnifred answered 3/4, 2013 at 15:52 Comment(0)
D
1

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();
Daubery answered 1/4, 2013 at 20:35 Comment(0)
V
-1

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.

Valentinvalentina answered 4/4, 2013 at 14:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.