【问题标题】:App.config add nested group to existing nodeApp.config 将嵌套组添加到现有节点
【发布时间】:2019-02-20 00:12:52
【问题描述】:

我必须在我的根设置组中保存 2 组不同的设置。它应该是这样的:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>    
    <sectionGroup name="ROOT_GROUP">
       <sectionGroup name="GROUP_1">
         ........................
         some_settings
         ........................
       </sectionGroup>
       <sectionGroup name="GROUP_2">
         ........................
         some_other_settings
         ........................
       </sectionGroup>
     </sectionGroup>
  </configSections>
................................
other_system_tags
................................
</configuration>

细微差别是我必须将它一个接一个地保存在代码中的不同位置。 (例如,GROUP_1 可以是连接字符串,GROUP_2 是一些环境设置,它们都由我的应用程序不同部分的用户填写)

我做了这个简单的测试类来得到预期的结果

[TestFixture]
public class Tttt
{
    private string ROOT_GROUP = "ROOT_GROUP";
    private string GROUP_1 = "GROUP_1";
    private string GROUP_2 = "GROUP_2";

    [Test]
    public void SaveSettingsGroups()
    {
        SaveGroup1();
        SaveGroup2();
        Assert.True(true);
    }

    private Configuration GetConfig()
    {
        var configFilePath = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
        var map = new ExeConfigurationFileMap { ExeConfigFilename = configFilePath };
        var config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
        return config;
    }

    private void SaveGroup1()
    {
        var config = GetConfig();

        var root = new UserSettingsGroup();

        config.SectionGroups.Add(ROOT_GROUP, root);

        config.Save(ConfigurationSaveMode.Modified);
        ConfigurationManager.RefreshSection(root.Name);

        var nested = new UserSettingsGroup();

        root.SectionGroups.Add(GROUP_1, nested);

        config.Save(ConfigurationSaveMode.Modified);
        ConfigurationManager.RefreshSection(nested.Name);             
    }

    private void SaveGroup2()
    {
        var config = GetConfig();

        var root = config.GetSectionGroup(ROOT_GROUP);

        var nested = new UserSettingsGroup();
        root.SectionGroups.Add(GROUP_2, nested);

        config.Save(ConfigurationSaveMode.Modified);
        ConfigurationManager.RefreshSection(nested.Name);
    }
}

但由于某种原因,这段代码的结果不同

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>    
    <sectionGroup name="ROOT_GROUP">
      <sectionGroup name="GROUP_1">
        ........................
        some_settings
        ........................
      </sectionGroup>
    </sectionGroup>
    <sectionGroup name="ROOT_GROUP">
      <sectionGroup name="GROUP_2">
      ........................
      some_other_settings
      ........................
      </sectionGroup>
    </sectionGroup>
  </configSections>
................................
other_system_tags
................................
</configuration>

ROOT_GROUP 节点是重复的,当然 Visual Studio 会向我抛出 ROOT_GROUP 已经存在的异常。显然,当我将新的嵌套组添加到现有的根组然后保存它时,我的问题隐藏在方法 SaveGroup2() 中 - 但为什么呢?

UPD 我刚刚添加了新方法

    private void SaveGroup3()
    {
        var config = GetConfig();

        var root = config.GetSectionGroup(ROOT_GROUP);
        var nested1 = root.SectionGroups.Get(0);

        var nested2 = new UserSettingsGroup();
        var nested3 = new UserSettingsGroup();

        nested1.SectionGroups.Add("GROUP_2", nested2);
        root.SectionGroups.Add("GROUP_3", nested3);
        config.Save(ConfigurationSaveMode.Modified);
        ConfigurationManager.RefreshSection(nested2.Name);
        ConfigurationManager.RefreshSection(nested3.Name);
    }

并在测试中替换它

[Test]
public void SaveSettingsGroups()
{
    SaveGroup1();
    SaveGroup3();
    Assert.True(true);
}

得到了这种奇怪的行为

  <sectionGroup name="ROOT_GROUP">
    <sectionGroup name="GROUP_1">
      <sectionGroup name="GROUP_2">
      </sectionGroup>
    </sectionGroup>
    <sectionGroup name="GROUP_3">
    </sectionGroup>
  </sectionGroup>

如您所见,奇怪之处在于结果完全符合预期。 ROOT_GROUP 不是重复的,因为我需要它,但是为什么它在 SaveGroup2() 中呢?我错过了 SaveGroup2() 中的某些内容吗?

UPD2 - 破解

刚刚尝试了一个简单的想法 - 如果我在添加新的嵌套元素之前清除 root_group 会怎样?

    private void SaveGroup2()
    {
        var config = GetConfig();

        var root = config.GetSectionGroup(ROOT_GROUP);

        var nested = new ConfigurationSectionGroup();

        //Copy exiting nested groups to array
        var gr = new ConfigurationSectionGroup[5];       
        root.SectionGroups.CopyTo(gr,0);
        gr[1] = nested;
        //<!----

        root.SectionGroups.Clear();

        config.Save(ConfigurationSaveMode.Modified);
        ConfigurationManager.RefreshSection(root.Name);

        root.SectionGroups.Add(gr[0].Name, gr[0]);
        root.SectionGroups.Add(GROUP_2, gr[1]);

        config.Save(ConfigurationSaveMode.Modified);
        ConfigurationManager.RefreshSection(root.Name);
    }

你可能怎么猜 - 它有效!

<sectionGroup name="ROOT_GROUP">
  <sectionGroup name="GROUP_1" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
  </sectionGroup>
  <sectionGroup name="GROUP_2" type="System.Configuration.ConfigurationSectionGroup, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" >
  </sectionGroup>
</sectionGroup>

我认为它看起来像一个错误,或者我错过了一些隐藏的东西。谁能解释一下我做错了什么?

【问题讨论】:

  • 我不会通过告诉你简单的答案来获得我的第 100 个(我知道它只说 97 个)赏金。避开ExeConfigurationFileMap 类或任何配置更改类,它们都很糟糕。配置文件只是 XML。使用 XML 类,例如 LINQ to XML。
  • 这绝对是一个错误。即使在您的 UPD 1 中,如果您的 Group_1 里面有东西,然后您将 sub SectionGroup 添加到它,它将复制所有根部分。我建议您改用自定义配置,因为此功能必须未经 Microsoft 测试。
  • @IgorTkachenko 感谢您的回复,我决定放弃配置中的 root_group。 P.S.程序员的世界很精彩,连微软都受制于其法律cs8.pikabu.ru/post_img/2016/06/23/9/1466695766198687223.jpg

标签: c# xml visual-studio configuration app-config


【解决方案1】:

我花了一段时间才弄清楚发生了什么,并且 tl;dr 在我看来,框架代码本身存在问题,特别是 method WriteUnwrittenConfigDeclarationsRecursive(SectionUpdates declarationUpdates, XmlUtilWriter utilWriter, int linePosition, int indent, bool skipFirstIndent)MgmtConfigurationRecord。我不想写长篇大论,但如果您希望可以调试 .Net 框架代码并亲自看看。

您可以通过以下方式修复您的代码:

1.将所有组保存在一起

private void SaveGroups()
{
    var config = GetConfig();
    var root = new ConfigurationSectionGroup();
    config.SectionGroups.Add(ROOT_GROUP, root);
    config.Save(ConfigurationSaveMode.Modified);
    ConfigurationManager.RefreshSection(root.Name);

    var nested = new UserSettingsGroup();
    root.SectionGroups.Add(GROUP_1, nested);

    nested = new UserSettingsGroup(); 
    root.SectionGroups.Add(GROUP_2, nested);

    config.Save(ConfigurationSaveMode.Modified);
    ConfigurationManager.RefreshSection(root.Name);
}

2。在添加新组项之前删除现有组项

private void SaveGroup2()
{
    var config = GetConfig();
    var root = config.SectionGroups[ROOT_GROUP];
    var existingGroups = new Dictionary<string, ConfigurationSectionGroup>();
    while (root.SectionGroups.Count > 0)
    {
        existingGroups.Add(root.SectionGroups.Keys[0], root.SectionGroups[0]);
        root.SectionGroups.RemoveAt(0);
    }

    config.Save(ConfigurationSaveMode.Modified);

    existingGroups.Add(GROUP_2, new UserSettingsGroup());
    foreach (var key in existingGroups.Keys)
    {
        existingGroups[key].ForceDeclaration(true);
        root.SectionGroups.Add(key, existingGroups[key]);
    }

    config.Save(ConfigurationSaveMode.Modified);
    ConfigurationManager.RefreshSection(root.Name);
}

【讨论】:

    【解决方案2】:

    在您的第一次更新中,您在根目录下的第一个条目下添加了 GROUP_2:

        //nested1 is now the first entry under root due to Get(0)
        var nested1 = root.SectionGroups.Get(0); 
    
        var nested2 = new UserSettingsGroup();
        var nested3 = new UserSettingsGroup();
    
        //I think you meant root here instead of nested1.
        nested1.SectionGroups.Add("GROUP_2", nested2);
    

    【讨论】:

    • 您是否尝试重现我的测试?你的回答毫无意义
    • 是的,当编码正确时,一切都完全按照它应该的方式工作。我对你在哪里理解有问题感到困惑。我上面的回答是我帮助您理解的最大尝试。
    猜你喜欢
    • 2021-07-21
    • 1970-01-01
    • 2018-05-31
    • 2020-10-28
    • 1970-01-01
    • 1970-01-01
    • 2017-12-11
    • 2020-09-13
    • 2021-12-20
    相关资源
    最近更新 更多