首页 > 解决方案 > 具有递归 ConfigurationElement 的自定义配置部分

问题描述

我正在尝试创建一个表示以下 xml 结构的自定义配置部分:

<observerSettings>
   <jobSettings>
      <filter key="location" value="de">
        <filter key="type" value="MyType1">
          <filter key="status" value="failed">
            <actions>
              <notify timespan="12.00:00:00">
                <mailSettings>
                  <mailAddress to="mail1@something.com" />
                  <mailAddress to="mail2@something.com" />
                </mailSettings>
              </notify>
              <remove timespan="14.00:00:00">
                <mailSettings>
                  <mailAddress to="mail1@something.com" />
                  <mailAddress to="mail2@something.com" />
                </mailSettings>
              </remove>
            </actions> 
          </filter>
        </filter>
      </filter>
   </jobSettings>
</observerSettings>

是这样定义的FilterConfigElement

internal class FilterConfigElement : ConfigurationElement, IFilterConfigElement
{
        [ConfigurationProperty("filter", IsRequired = false)]
        public FilterConfigElement ChildFilter => base["filter"] as FilterConfigElement;

        [ConfigurationProperty("actions", IsRequired = false)]
        public ActionsConfigElement Actions => base["actions"] as ActionsConfigElement;

        [ConfigurationProperty("key", IsRequired = true)]
        public string Key => base["key"] as string;

        [ConfigurationProperty("value", IsRequired = false)]
        public string Value => base["value"] as string;
}

当访问如下配置部分时,应用程序崩溃并出现StackOverflow异常:

internal class ObserverSettings : ConfigurationSection, IObserverSettings
{
   public static IObserverSettings Instance { get; private set; } = ConfigurationManager.GetSection("observerSettings") as ObserverSettings;

   [ConfigurationProperty("jobSettings")]
   protected JobSettingsCollection JobSettingsCollection => base["jobSettings"] as JobSettingsCollection;

   public virtual IJobSettingsCollection JobSettings => JobSettingsCollection;
}

所以我假设ConfigurationManager正在创建这个具有无限深度的结构,并且在filter到达最后一个元素时不会停止。这可以以某种方式限制吗?甚至支持这种结构吗?

标签: c#recursionconfigurationmanager

解决方案


好的,在深入研究实现之后ConfigurationElement,似乎根本不可能按照我尝试的方式创建递归结构。

问题的原因是在调用之后执行PropertiesFromTypewhere 属性的分配,从而创建了一个无休止的递归 where is always 。s_propertyBagsCreatePropertyBagFromTypepropertiesnull

private static bool PropertiesFromType(Type type, out ConfigurationPropertyCollection result)
{
   ConfigurationPropertyCollection properties = (ConfigurationPropertyCollection)s_propertyBags[type];
   result = null;
   bool firstTimeInit = false;
   if (properties == null) /*code omitted*/
   {
      properties = CreatePropertyBagFromType(type);
      s_propertyBags[type] = properties;
      firstTimeInit = true;
   }
   result = properties;
   return firstTimeInit;
}

来源:https ://referencesource.microsoft.com/#System.Configuration/System/Configuration/ConfigurationElement.cs

编辑:

保持某种“递归”结构的唯一解决方法是将所有 child 包装FilterConfigElement成一个ConfigurationElementCollectionwith element name childFilter。这导致遵循不太好但可接受的配置结构:

<jobSettings>
  <filter key="location" value="de">
    <childFilter>
      <filter key="type" value="MyType1">
        <childFilter>
          <filter key="status" value="failed">
            <actions>
              <!-- ... -->
            </actions>
          </filter>
        </childFilter>
      </filter>
    </childFilter>
  </filter>
</jobSettings>

来源:c# 中的递归自定义配置


推荐阅读