3

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

例如

<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;
    }
}

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

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

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

4

2 回答 2

1

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

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

例如

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会阻止元素被写入配置文件。例如

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();
于 2012-12-14T00:27:08.197 回答
0

我认为您应该对PostDeserialize从类中提取的方法执行此操作ConfigurationElement,而不对您的业务逻辑执行此操作。

例如:

protected override void PostDeserialize()
{
    base.PostDeserialize();
    if (FirstSubTypeConfig != null && SecondTypeCOnfig != null)
    {
        throw new ConfigurationErrorsException("Only an element is allowed.");
    }
}
于 2019-10-03T14:21:58.240 回答