在外部文件中编写 appSettings

13

我有一个配置文件 app.exe.config,其中 appSettings 部分类似于这样:

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

app.file.config文件大致如下:

<?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>

我需要在运行时编辑var1、var2和var3,而且我有类似以下的代码:

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");
当我运行config.Save()时....文件app.file.config具有一个名为"file"的属性的appSettings节点。此属性的值为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>

现在,如果我尝试加载配置文件,我会在app.file.config中得到异常消息“未识别的属性'file'。请注意,属性名称区分大小写。”

如果我手动删除文件属性,则配置文件将被正确加载。

有什么想法吗?

我如何避免在保存配置文件时编写文件属性。

谢谢


从未这样做过,如果省略 ConfigSource = "app.file.config" 这行会发生什么? - kenny
Kenny,我不明白你的意思。能否请你详细解释一下? - J19
1
当您移除代码 "config.AppSettings.SectionInformation.ConfigSource = "app.file.config";" 时会发生什么? - kenny
1
你的第一个标签有错别字,对吧?因为你把它关闭了。 - Vitor Canova
感谢Vitor Canova。这是一个打字错误。 - J19
当我删除 "config.AppSettings.SectionInformation.ConfigSource = "app.file.config";" 时,设置将存储在 app.exe.config 文件中而不是 app.file.config 文件中。 - J19
3个回答

15

使用外部配置文件对应用程序是透明的,

这部分是没问题的。

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

还有这个:

<?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>

将您的代码更改为以下内容:

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

引用外部配置文件对应用程序是透明的,因此您不必直接调用它。您可以使用配置管理器中的默认appSetting部分。

祝好运


3
你好,Tomer Klein。按照你的建议,设置应该存储在app.exe.config中,而不是app.file.config。 - J19
我如何访问Application.ExecutablePath? - Bastien Vandamme

5
一个更全面的防止混淆的答案:
设置:
  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();
    
    }
    

这将导致App.Settings.config文件被更新到文件系统上,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<appSettings>
  <add key="test" value="NEW" />
  <add key="testExternalOnly" value="NEWEXTERNAL" />
</appSettings>

如果我理解正确,你的回答意味着没有解决方案?如果是这样,请查看被接受的答案。 - Amessihel
@Amessihel 你在新的Framework4.8控制台应用程序中测试过吗?你得到了什么结果?我在我的答案中包含了“TEST4”。如果你的测试代码不同并且有不同的结果,我很乐意审查它。 - OzBob
我在.NET 4.0和Visual Studio 2010 x86(32位)中进行了测试。@J19的解决方案有效。 - Amessihel
原始答案已经进行了编辑,并且现在使用 Uri 来表示 Exe 路径,config.AppSettings.SectionInformation.ConfigSource = "App.Settings.config"。 - OzBob

3

将配置文件声明为:

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

来自代码

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

请注意,我使用 GetSection("appSettings") 而不是 config.AppSettings.Settings
感谢所有在StackOverflow上帮助他人的人。

1
嗨,Christopher Painter,这并不完全相同。在我的情况下,关键点是“AppSettingsSection myAppSettings = config.GetSection("appSettings")”。使用GetSection是解决方案。感谢Tomer Klein的回答,但对我来说,我需要做一些更改。 - J19
2
@christoper-painter,@j19实际上有点眉目。我认为他想在程序化保存设置时更新app.file.config而不是app.exe.config。至少这就是我想做的事情,而configSource属性而不是file正是能够实现这一点的,参见https://dev59.com/2Gw05IYBdhLWcg3w72I0。 - Brian Ensink
应该是最受赞同的答案。这不公平。 - Amessihel
请为“Application”类提供一个完全限定的命名空间。 - OzBob
1
@OzBob,实际上当我测试这个解决方案时,我没有使用 Application.ExecutablePath,而是使用了 System.Reflection.Assembly.GetExecutingAssembly().CodeBase。它返回一个 URI,所以我使用 new Uri(codebase).LocalPath 获取本地路径。虽然我不喜欢为单一用途实例化对象,但由于每次执行只需要执行一次,所以这样做没问题。 - Amessihel
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接