C# 具有一组参数的多个实例的.NET配置

C# 具有一组参数的多个实例的.NET配置,c#,.net,configuration,C#,.net,Configuration,我有一个可以连接到多个服务器的应用程序。服务器的实际数量直到运行时才知道,并且可能每天都在变化。完全定义服务器需要几个实际参数 我正在尝试使用.NET对应用程序配置的支持来配置应用程序 配置文件类似于: <?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <sectionGroup name="userSetting

我有一个可以连接到多个服务器的应用程序。服务器的实际数量直到运行时才知道,并且可能每天都在变化。完全定义服务器需要几个实际参数

我正在尝试使用.NET对应用程序配置的支持来配置应用程序

配置文件类似于:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <sectionGroup
           name="userSettings"
            type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
            <section name="server"
                type="System.Configuration.SingleTagSectionHandler"
                allowExeDefinition="MachineToLocalUser"
                requirePermission="false" />
        </sectionGroup>
    </configSections>
    <userSettings>
        <server name="washington">
            <add name="host" value="abc.presidents.com"/>
            <add name="port" value="1414"/>
            <add name="credentials" value="george"/>
        </server>
        <server name="adams">
            <add name="host" value="def.presidents.com"/>
            <add name="port" value="1419"/>
            <add name="credentials" value="john"/>
        </server>
        <!--insert more server definitions here -->
    </userSettings>
</configuration>
这将从foreach引发异常,并生成以下输出:

    System.Configuration.Configuration
    System.Configuration.UserSettingsGroup: userSettings
    System.Configuration.ConfigurationSectionCollection: 1
    Exception: Sections must only appear once per config file.  See the help topic <location> for exceptions.
我尝试过主题的其他变体(嵌套的分区组等),但没有找到解决方案。我发现的各种教程示例似乎希望我为每台服务器创建一个单独的类。这显然是不切实际的,而且应该是不必要的,因为所有服务器都是平等创建的

问题:

  • System.Configuration是否支持一组相关设置(如结构数组)的概念
  • 如果是的话。。怎么做
  • 如果不是。。是否有另一种方法来存储支持此概念的持久配置信息,或者我将不得不使用自己的方法
进度报告 根据Robert McKee的部分回答,我对xml进行了如下修改:

            <section name="servers"
                type="System.Configuration.DefaultSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"

没有使用自定义配置节,但从纯逻辑的角度来看,这不是更合适:

<userSettings>
    <servers>
        <add name="washington" host="abc.presidents.com" port="1414" credentials="george"/>
        <add name="adams" host="def.presidents.com" port="1419" credentials="john"/>
        <!--insert more server definitions here -->
    </servers>
    <!-- insert more user settings here -->
</userSettings>

您可以通过其他方式来实现,但是如果您想要一个“server”集合,那么它必须位于类似“servers”的分组元素中。不能在一个父元素中只包含多个“服务器”,而该父元素也可以包含其他类型的子元素。组中的标记几乎总是“添加”

无论如何,“System.Configuration.SingleTagSectionHandler”绝对不是正确的类型。

  • 如果不创建自定义特性类,则无法支持特性集集合
  • 对创建自定义属性类的支持非常好
  • 创建自定义属性类的文档非常糟糕,但是我最终找到了一个合适的方法来帮助我找到答案
配置文件 我得到的app.config文件是:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <sectionGroup name="userSettings" 
                      type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
            <section name="executiveBranch" 
                     type="PropProto.Properties.ExecutiveBranchSection, PropProto, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" 
                     allowExeDefinition="MachineToLocalUser" 
                     requirePermission="false" />
        </sectionGroup>
    </configSections>
    <userSettings>
        <executiveBranch>
            <presidents>
                <president key="first"
                           name="George Washington"
                           legacy="The Fother of Our County"
                           />
                <president key="honestAbe"
                           name="Abraham Lincoln"
                           legacy="Freed the Slaves"
                           />
                <president key="who"
                           name="Chester Arthur"
                           />
                <president key="dubya"
                           name="George W. Bush"
                           legacy="Mission Accomplished!!!"
                           />
                <president key="barack"
                           name="Barack Obama"
                           legacy="Affordable Health Care"
                           />

            </presidents>
        </executiveBranch>
    </userSettings>
</configuration>
自定义属性类 以及实现所有这些功能的自定义类:

public class ExecutiveBranchSection : ConfigurationSection
{
    public const string Tag = "executiveBranch";
    [ConfigurationProperty(PresidentCollection.Tag)]
    public PresidentCollection Presidents { get { return (PresidentCollection)base[PresidentCollection.Tag]; } }
}

[ConfigurationCollection(typeof(President),
    CollectionType = ConfigurationElementCollectionType.BasicMap,
    AddItemName = President.Tag)]
public class PresidentCollection : ConfigurationElementCollection
{
    public const string Tag = "presidents";
    protected override string ElementName { get { return President.Tag; } }

    public President this[int index]
    {
        get { return (President)base.BaseGet(index); }
        set
        {
            if (base.BaseGet(index) != null)
            {
                base.BaseRemoveAt(index);
            }

            base.BaseAdd(index, value);
        }
    }

    new public President this[string name] { get { return (President)base.BaseGet(name); } }

    protected override ConfigurationElement CreateNewElement()
    {
        return new President();
    }

    protected override object GetElementKey(ConfigurationElement element)
    {
        return (element as President).Key;
    }
}

public class President : ConfigurationElement
{
    public const string Tag = "president";
    [ConfigurationProperty("key", IsRequired = true)]
    public string Key { get { return (string)base["key"]; } }
    [ConfigurationProperty("name", IsRequired = true)]
    public string Name { get { return (string)base["name"]; } }
    [ConfigurationProperty("legacy", IsRequired = false)]
    public string Legacy { get { return (string)base["legacy"]; } }
}

有趣。我从未见过
add
元素使用了
name
value
属性之外的任何东西。我正在尝试这个,但遇到了其他问题。请继续关注……奇怪。你从未见过连接字符串部分?还是页面/名称空间?还是HttpHandler?模块?SqlDependencies?输出缓存设置?编译/程序集?尽管如此,system.webserver/runtime/assemblybinding确实有多个dependentAssembly子项,这些子项不使用“add”作为标记,而是使用“dependentAssembly”作为标记及其自己的子项。所以你也可以这样做,只是不太常见。讽刺不是特别受欢迎(或必要),但,是的,我是一个使用系统的新手。配置,我不与数据库,或http,或。。。因此,我没有在MSDN中的大量但基本上没有帮助的文档中找到这些途径。令人惊讶的是,他们能有效地告诉你一切,除了你想知道的。(我知道,这是我的讽刺。)对不起,我不是故意讽刺的,只是遇到一些试图创建自定义配置但尚未使用过web或数据库的人时,这种情况并不常见。感谢您发布您的最终工作结果!我的灵感来源于此以及ConnectionStringSettingsCollection的.Net Framework源代码,它看起来与您在这里看到的非常相似。我将此链接发布到.Net参考源,因为它验证了您的方法,并包含大量其他有用的实现。
<userSettings>
    <servers>
        <add name="washington" host="abc.presidents.com" port="1414" credentials="george"/>
        <add name="adams" host="def.presidents.com" port="1419" credentials="john"/>
        <!--insert more server definitions here -->
    </servers>
    <!-- insert more user settings here -->
</userSettings>
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <sectionGroup name="userSettings" 
                      type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
            <section name="executiveBranch" 
                     type="PropProto.Properties.ExecutiveBranchSection, PropProto, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" 
                     allowExeDefinition="MachineToLocalUser" 
                     requirePermission="false" />
        </sectionGroup>
    </configSections>
    <userSettings>
        <executiveBranch>
            <presidents>
                <president key="first"
                           name="George Washington"
                           legacy="The Fother of Our County"
                           />
                <president key="honestAbe"
                           name="Abraham Lincoln"
                           legacy="Freed the Slaves"
                           />
                <president key="who"
                           name="Chester Arthur"
                           />
                <president key="dubya"
                           name="George W. Bush"
                           legacy="Mission Accomplished!!!"
                           />
                <president key="barack"
                           name="Barack Obama"
                           legacy="Affordable Health Care"
                           />

            </presidents>
        </executiveBranch>
    </userSettings>
</configuration>
var exeConfiguration = ConfigurationManager.OpenExeConfiguration(
      ConfigurationUserLevel.PerUserRoamingAndLocal);
var userSettings = exeConfiguration.GetSectionGroup("userSettings");
var executiveBranch = (ExecutiveBranchSection)userSettings.Sections.Get(
        ExecutiveBranchSection.Tag);
var presidents = executiveBranch.Presidents;
foreach (President president in presidents)
{
    Console.WriteLine("{0}: {1}", president.Name, president.Legacy);
}
public class ExecutiveBranchSection : ConfigurationSection
{
    public const string Tag = "executiveBranch";
    [ConfigurationProperty(PresidentCollection.Tag)]
    public PresidentCollection Presidents { get { return (PresidentCollection)base[PresidentCollection.Tag]; } }
}

[ConfigurationCollection(typeof(President),
    CollectionType = ConfigurationElementCollectionType.BasicMap,
    AddItemName = President.Tag)]
public class PresidentCollection : ConfigurationElementCollection
{
    public const string Tag = "presidents";
    protected override string ElementName { get { return President.Tag; } }

    public President this[int index]
    {
        get { return (President)base.BaseGet(index); }
        set
        {
            if (base.BaseGet(index) != null)
            {
                base.BaseRemoveAt(index);
            }

            base.BaseAdd(index, value);
        }
    }

    new public President this[string name] { get { return (President)base.BaseGet(name); } }

    protected override ConfigurationElement CreateNewElement()
    {
        return new President();
    }

    protected override object GetElementKey(ConfigurationElement element)
    {
        return (element as President).Key;
    }
}

public class President : ConfigurationElement
{
    public const string Tag = "president";
    [ConfigurationProperty("key", IsRequired = true)]
    public string Key { get { return (string)base["key"]; } }
    [ConfigurationProperty("name", IsRequired = true)]
    public string Name { get { return (string)base["name"]; } }
    [ConfigurationProperty("legacy", IsRequired = false)]
    public string Legacy { get { return (string)base["legacy"]; } }
}