12

I have a config file app.exe.config and appSettings section has something like this:

<configuration>
    <appSettings configSource="app.file.config" />
</configuration>

app.file.config file has something like this:

<?xml version="1.0" encoding="utf-8" ?>
<appSettings>
  <add key="var1" value="value 1" />
  <add key="var2" value="value 2" />
  <add key="var3" value="value 3" />
</appSettings>

I need to edit var1, var2 and var3 at runtime and I have code like this:

Configuration config = ConfigurationManager.OpenExeConfiguration("...path\app.exe);

config.AppSettings.SectionInformation.ConfigSource = "app.file.config";

config.AppSettings.Settings["var1"].Value = "value 11";
config.AppSettings.Settings["var2"].Value = "value 22";
config.AppSettings.Settings["var3"].Value = "value 33";
config.Save(ConfigurationSaveMode.Modified);

ConfigurationManager.RefreshSection("appSettings");

When I run config.Save.... the file app.file.config has a appSettings node with an attribute "file". This attribute has the value to app.file.config

<appSettings file="app.file.config">
<add key="var1" value="value 1" />
  <add key="var2" value="value 2" />
  <add key="var3" value="value 3" />
</appSettings>

Now, if I try to load the config file, I have an exception with message "Unrecognized attribute 'file'. Note that attribute names are case-sensitive." in app.file.config.

If I delete the file attribute manually, the configuration file is loaded properly.

Any ideas?

How can avoid to write file attribute when I save config files.

Thanks

J19
  • 667
  • 2
  • 10
  • 27
  • never did this, what happens if you leave out the line ConfigSource = "app.file.config"; – kenny Dec 29 '14 at 15:36
  • Kenny, I don't understand you. Please, can you explain more in detail? – J19 Dec 29 '14 at 16:25
  • 1
    what happens when you remove your code "config.AppSettings.SectionInformation.ConfigSource = "app.file.config";" – kenny Dec 29 '14 at 16:56
  • 1
    There is a typo in your first tag right? because you are closing it. – Vitor Canova Dec 29 '14 at 18:34
  • Thanks Vitor Canova. It's was a typing error – J19 Dec 30 '14 at 10:09
  • When I remove "config.AppSettings.SectionInformation.ConfigSource = "app.file.config";" the settings are stored in app.exe.config file not in app.file.config – J19 Dec 30 '14 at 10:22

3 Answers3

14

using an external config file is transparent for the application,

this part is o.k

</configuration>
    <appSettings configSource="app.file.config" />
</configuration>

and also this:

<?xml version="1.0" encoding="utf-8" ?>

<appSettings>
  <add key="var1" value="value 1" />
  <add key="var2" value="value 2" />
  <add key="var3" value="value 3" />
</appSettings>

change your code to be like this:

Configuration config = ConfigurationManager.OpenExeConfiguration(Application.ExecutablePath);
config.AppSettings.Settings["var1"].Value = "value 11";
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");

referring an external configuration file is transparent to the application, so you don't have to call it directly. you can use the default appSetting section in the configuration manager.

Good luck

t3chb0t
  • 16,340
  • 13
  • 78
  • 118
Tomer Klein
  • 436
  • 2
  • 6
5

A more complete answer to prevent confusion:

Setup:

  1. Commandline project called 'app'
  2. app.exe.config file, App.config:

    <appSettings file="App.Settings.config"></appSettings>
    
  3. App.Settings.config file with 'Copy to Output Directory'= 'Copy Always'

    <?xml version="1.0" encoding="utf-8"?>
    <appSettings>
      <add key="test" value="OVERRIDDEN"/>
    </appSettings>
    
  4. Program.cs:

    static void Main(string[] args)
    {
        try
        {
            Console.WriteLine("Local Config sections");
            var exepath = (new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase)).LocalPath;
            Configuration config = ConfigurationManager.OpenExeConfiguration(exepath);
    
            config.AppSettings.SectionInformation.ConfigSource = "App.Settings.config";
    
            Console.WriteLine("BEFORE[test]=" + config.AppSettings.Settings["test"].Value);
            Console.WriteLine($"BEFORE[testExternalOnly]={config.AppSettings.Settings["testExternalOnly"]?.Value}");
    
            //to avoid: Error CS0266
            //Explicitly cast 'System.Configuration.AppSettingsSection'
            AppSettingsSection myAppSettings = (AppSettingsSection)config.GetSection("appSettings");
    
            myAppSettings.Settings["test"].Value = "NEW";
            if (!myAppSettings.Settings.AllKeys.Contains("testExternalOnly"))
                myAppSettings.Settings.Add("testExternalOnly", "NEWEXTERNAL");
    
            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("appSettings");
    
            //Read updated config
            Console.WriteLine("AFTER[test]=" + config.AppSettings.Settings["test"].Value);
            Console.WriteLine("AFTER[testExternalOnly]=" + config.AppSettings.Settings["testExternalOnly"].Value);
    
            Console.WriteLine("AFTER CONFIG EXTERNAL FILE: " + System.IO.File.ReadAllText("App.Settings.config"));
    
            Console.WriteLine("AFTER CONFIG FILE: " + System.IO.File.ReadAllText(System.AppDomain.CurrentDomain.FriendlyName + ".config"));
    
    
            //Shut current config
            config = null;
    
            //Open config
            config = ConfigurationManager.OpenExeConfiguration(exepath);
            config.AppSettings.SectionInformation.ConfigSource = "App.Settings.config";
    
            Console.WriteLine("AFTER[test]=" + config.AppSettings.Settings["test"].Value);
            Console.WriteLine("AFTER[testExternalOnly]=" + config.AppSettings.Settings["testExternalOnly"].Value);
    
            Console.WriteLine("AFTER CONFIG EXTERNAL FILE: " + System.IO.File.ReadAllText("App.Settings.config"));
    
            Console.WriteLine("AFTER CONFIG FILE: " + System.IO.File.ReadAllText(System.AppDomain.CurrentDomain.FriendlyName + ".config"));
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        Console.WriteLine("press the ENTER key to end");
        Console.ReadLine();
    
    }
    

This will result in App.Settings.config file updated to be on the filesystem as:

<?xml version="1.0" encoding="utf-8"?>
<appSettings>
  <add key="test" value="NEW" />
  <add key="testExternalOnly" value="NEWEXTERNAL" />
</appSettings>
OzBob
  • 4,227
  • 1
  • 39
  • 48
  • If I understand correctly, your answer imply there isn't a solution? If so, please see the accepted answer. – Amessihel Dec 18 '19 at 00:29
  • @Amessihel Did you test it in a new Framework4.8 console app? What results did you get? I have included 'TEST4' in my answer. If your test code is different and has different results I would be more than happy to review it. – OzBob Dec 19 '19 at 06:18
  • I tested it in .NET 4.0 with Visual Studio 2010 x86 (32 bits). @J19 solution works. – Amessihel Dec 19 '19 at 10:01
  • original answer edited and now works with a Uri for the Exe path and config.AppSettings.SectionInformation.ConfigSource = "App.Settings.config"; – OzBob Jan 07 '20 at 04:24
2

Declare the config file as this:

<appSettings configSource="app.file.config">
<add key="var1" value="value 1" />
  <add key="var2" value="value 2" />
  <add key="var3" value="value 3" />
</appSettings>

And from code

Configuration config = ConfigurationManager.OpenExeConfiguration(Application.ExecutablePath);
AppSettingsSection myAppSettings = config.GetSection("appSettings")
myAppSettings.Settings["var1"].Value = "value 11";
config.Save(ConfigurationSaveMode.Modified);

Note that I use GetSection("appSettings") instead of config.AppSettings.Settings

Thanks to all that help people in StackOverflow.

Leandro Bardelli
  • 10,561
  • 15
  • 79
  • 116
J19
  • 667
  • 2
  • 10
  • 27
  • 1
    Hi Christopher Painter, it's not exacly the same. In my scenario, the key point was "AppSettingsSection myAppSettings = config.GetSection("appSettings")". Using GetSection was the solution. Thanks to Tomer Klein for his answer but, for me I need a few changes – J19 Jan 27 '15 at 00:04
  • 2
    @christoper-painter, @j19 is actually onto something. I think he wants to update the `app.file.config` instead of the `app.exe.config` when saving settings programatically. At least that is what I wanted to do and the `configSource` attribute instead of `file` is exactly what does that, see http://stackoverflow.com/questions/6940004/asp-net-web-config-configsource-vs-file-attributes – Brian Ensink Aug 19 '15 at 17:39
  • Should be the most upvoted answer. This isn't fair. – Amessihel Dec 18 '19 at 00:26
  • Please provide a fully qualified namespace for the 'Application' class – OzBob Dec 19 '19 at 06:20
  • 1
    @OzBob, actually when I tested this solution, I didn't use `Application.ExecutablePath`, but [`System.Reflection.Assembly.GetExecutingAssembly().CodeBase`](https://stackoverflow.com/a/837501/4375327). It returns an URI, so I get the local path using `new Uri(codebase).LocalPath`. I don't like instanciating object for a single usage, but since it's done once per execution that's ok. – Amessihel Dec 19 '19 at 10:08
  • @Amessihel Do you get a cast error on line 2? (AppSettingsSection) is required before the 'config.GetSection' in my test of your code. – OzBob Jan 06 '20 at 00:37
  • @OzBob, I use VB.NET so I'm not sure the same rules apply. The cast error doesn't surprise me at all anyways, since `AppSettingsSection` is derived from `ConfigurationSection`, and `getSection()` returns the last one type. – Amessihel Jan 06 '20 at 01:09
  • @Amessihel I changed Exe path into OpenExeConfiguration and now config.AppSettings.SectionInformation.ConfigSource = "App.Settings.config"; works! – OzBob Jan 07 '20 at 04:23