如何设置互斥的自定义配置元素?

时间:2012-12-12 16:43:48

标签: c# .net

我正在使用.NET配置API编写自定义配置部分。我想定义一个可以只有两个子元素之一的部分,

e.g。

<MyCustomSection>
    <myItems>
        <myItemType name="1">
            <firstSubTypeConfig />
        </myItemType>
        <myItemType name="2">
            <secondSubTypeConfig />
        </myItemType>
    </myItems>
</MyCustomSection>

目前,我的章节定义如下:

public class MyCustomSection : ConfigurationSection
{
    public override bool IsReadOnly()
    {
        return false;
    }

    [ConfigurationProperty("myItems")]
    public MyItemsCollection MyItems 
    { 
        get { return (MyItemsCollection)base["myItems"]; }
        set { base["myItems"] = value; }
    }
}

[ConfigurationCollection(typeof(MyItemType), AddItemName="myItemType",
    CollectionType=ConfigurationElementCollectionType.BasicMap)]
public class MyItemsCollection : ConfigurationElementCollection
{
    public override bool IsReadOnly()
    {
        return false;
    }

    public override ConfigurationElementCollectionType CollectionType
    {
        get { return ConfigurationElementCollectionType.BasicMap; }
    }

    protected override string ElementName
    {
        get { return "myItemType"; }
    }

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

    protected override object GetElementKey(ConfigurationElement element)
    {
        return (element as MyItemType).Name;
    }
}


public class MyItemType : ConfigurationElement
{
    public override bool IsReadOnly()
    {
        return false;
    }

    [ConfigurationProperty("name", IsRequired=true)]
    public string Name 
    { 
        get { return (string)base["name"]; }
        set { base["name"] = value; }
    }

    [ConfigurationProperty("firstSubTypeConfig")]
    public FirstSubTypeConfig FirstSubTypeConfig 
    { 
        get { return (FirstSubTypeConfig)base["firstSubTypeConfig"]; }
        set { base["firstSubTypeConfig"] = value; }

    }

    [ConfigurationProperty("secondSubTypeConfig")]
    public SecondSubTypeConfig SecondSubTypeConfig 
    { 
        get { return (SecondSubTypeConfig)base["secondSubTypeConfig"]; }
        set { base["secondSubTypeConfig"] = value; }
    }
}

public class FirstSubTypeConfig : ConfigurationElement
{
    public override bool IsReadOnly()
    {
        return false;
    }
}

public class SecondSubTypeConfig : ConfigurationElement
{
    public override bool IsReadOnly()
    {
        return false;
    }
}

配置也是以编程方式修改和保存的,目前正在保存 配置部分将添加secondSubTypeConfig元素,即使我只指定了 firstSubTypeConfig元素。

我的第一个想法是为FirstSubTypeConfigSecondSubTypeConfig引入一个公共基类,但我不清楚配置api是否或如何处理它。

如何设置互斥的自定义配置元素?

2 个答案:

答案 0 :(得分:1)

我不确定这是“正确的”方法,但这很有效。

问题中编写的代码将加载配置文件。您可以检查ElementInformation.IsPresent属性以验证是否包含一个元素。

e.g。

var custom = (MyCustomSection)ConfigurationManager.GetSection("MyCustomSection");
foreach (MyItemType itemType in custom.MyItems)
{
    if (itemType.FirstSubTypeConfig.ElementInformation.IsPresent 
        && itemType.SecondSubTypeConfig.ElementInformation.IsPresent)
    {
        throw new ConfigurationErrorsException("At most one of firstSubTypeConfig or secondSubTypeConfig can be specified in a myItemType element");
    }
    else if (!itemType.FirstSubTypeConfig.ElementInformation.IsPresent
        && !itemType.SecondSubTypeConfig.ElementInformation.Ispresent)
    {
        throw new ConfigurationErrorsException("Either a firstSubTypeConfig or a secondSubTypeConfig element must be specified in a myItemType element");
    }
}

至于保存配置,似乎检查ElementInformation.IsPresent并明确将其设置为null将阻止该元素被写入配置文件。 e.g。

var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var custom = (MyCustomSection)config.GetSection("MyCustomSection");

//make modifications against the custom variable ...

foreach (MyItemType itemType in custom.MyItems)
{
    if (!itemType.FirstSubTypeConfig.ElementInformation.IsPresent)
        itemType.FirstSubTypeConfig = null;
    if (!itemType.SecondSubTypeConfig.ElementInformation.IsPresent)
        itemType.SecondSubTypeConfig = null;  
}

config.Save();

答案 1 :(得分:0)

我认为您应该使用PostDeserialize类中提出的ConfigurationElement方法执行此操作,而不要在您的业务逻辑上执行此操作。

例如:

protected override void PostDeserialize()
{
    base.PostDeserialize();
    if (FirstSubTypeConfig != null && SecondTypeCOnfig != null)
    {
        throw new ConfigurationErrorsException("Only an element is allowed.");
    }
}