简单的自定义配置部分,包含.NET4中的集合

Ron*_*erg 10 .net c# system.configuration .net-4.0

我正在尝试为.NET4应用程序编写一个非常简单的自定义配置部分.我的目标是:

<configuration>
  <configSections>
    <section name="myServices" type="My.ConfigSection, My.Assembly" />
  </configSections>
  <myServices>
    <add name="First" />
    <add name="Second" />
  </myServices>
</configuration>
Run Code Online (Sandbox Code Playgroud)

但是,ConfigurationErrorsException当我打电话时,我不断得到:'无法识别的元素'添加'' ConfigurationManager.GetSection("myServices").我已经盯着它看了一段时间,但还没弄明白我做错了什么.以下是我的代码.这是三大类:ConfigSection,MyServiceSettingsCollectionMyServiceSettings.

首先是代表整个配置部分的类.它有一个无名的默认类型集合MyServiceSettingsCollection.该IsDefaultCollection属性应该允许我从根元素直接"添加"到我的集合.

public sealed class ConfigSection : ConfigurationSection
{
  private static readonly ConfigurationProperty _propMyServices;

  private static readonly ConfigurationPropertyCollection _properties;

  public static ConfigSection Instance { get { return _instance; } }

  static ConfigSection()
  {
    _propMyServices = new ConfigurationProperty(
          null, typeof(MyServiceSettingsCollection), null,
          ConfigurationPropertyOptions.IsDefaultCollection);
    _properties = new ConfigurationPropertyCollection { _propMyServices };
  }

  [ConfigurationProperty("", IsDefaultCollection = true)]
  public MyServiceSettingsCollection MyServices
  {
    get { return (MyServiceSettingsCollection) base[_propMyServices]; }
    set { base[_propMyServices] = value; }
  }

  protected override ConfigurationPropertyCollection Properties
  { get { return _properties; } }
}
Run Code Online (Sandbox Code Playgroud)

接下来,集合类本身.它是类型AddRemoveClearMap.

[ConfigurationCollection(typeof(MyServiceSettings),
    CollectionType = ConfigurationElementCollectionType.AddRemoveClearMap)]
public sealed class MyServiceSettingsCollection : ConfigurationElementCollection
{
  public MyServiceSettings this[int index]
  {
    get { return (MyServiceSettings) BaseGet(index); }
    set
    {
      if (BaseGet(index) != null) { BaseRemoveAt(index); }
      BaseAdd(index, value);
    }
  }

  public new MyServiceSettings this[string key]
  {
    get { return (MyServiceSettings) BaseGet(key); }
  }

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

  protected override object GetElementKey(ConfigurationElement element)
  {
    return ((MyServiceSettings) element).Key;
  }
}
Run Code Online (Sandbox Code Playgroud)

最后是集合中元素的类.目前,这个类有一个属性,但稍后会有更多(这阻止我使用NameValueSectionHandler).

public class MyServiceSettings : ConfigurationElement
{
  private static readonly ConfigurationProperty _propName;

  private static readonly ConfigurationPropertyCollection properties;

  static MyServiceSettings()
  {
    _propName = new ConfigurationProperty("name", typeof(string), null, null,
                                          new StringValidator(1),
                                          ConfigurationPropertyOptions.IsRequired |
                                          ConfigurationPropertyOptions.IsKey);
    properties = new ConfigurationPropertyCollection { _propName };
  }

  [ConfigurationProperty("name", DefaultValue = "",
        Options = ConfigurationPropertyOptions.IsRequired |
                  ConfigurationPropertyOptions.IsKey)]
  public string Name
  {
      get { return (string) base[_propKey]; }
      set { base[_propKey] = value; }
  }

  protected override ConfigurationPropertyCollection Properties
  { get { return properties; } }
}
Run Code Online (Sandbox Code Playgroud)

Ron*_*erg 12

好吧,我发现了看似随意的修复.而不是这个:

[ConfigurationProperty("", IsDefaultCollection = true)]
public ProvisiorServiceSettingsCollection ProvisiorServices
{ ... }
Run Code Online (Sandbox Code Playgroud)

你应该使用:

[ConfigurationProperty("", Options = ConfigurationPropertyOptions.IsDefaultCollection)]
public ProvisiorServiceSettingsCollection ProvisiorServices
{ ... }
Run Code Online (Sandbox Code Playgroud)

不知道两者之间有什么区别.对我来说,它们看起来非常相似......或者至少,没有任何关于为什么一个人优先于另一个人的建议.


Nic*_*tby 5

由于我在这方面花了很多时间,所以我想添加一个我刚刚在这次提交中实现的真实世界示例:https ://github.com/rhythmagency/formulate/commit/4d2a95e1a82eb6b3500ab0869b8f8b15bd3deaa9

这是我的 web.config 目标(我能够实现):

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <sectionGroup name="formulateConfiguration">
      <section name="templates" type="formulate.app.Configuration.TemplatesConfigSection, formulate.app" requirePermission="false"/>
    </sectionGroup>
  </configSections>
  <formulateConfiguration>
    <templates>
      <template name="Responsive" path="~/Views/Formulate/Responsive.Bootstrap.Angular.cshtml" />
    </templates>
  </formulateConfiguration>
</configuration>
Run Code Online (Sandbox Code Playgroud)

这是最高级别“模板”配置部分的类:

namespace formulate.app.Configuration
{

    // Namespaces.
    using System.Configuration;


    /// <summary>
    /// A configuration section for Formulate templates.
    /// </summary>
    public class TemplatesConfigSection : ConfigurationSection
    {

        #region Properties

        /// <summary>
        /// The templates in this configuration section.
        /// </summary>
        [ConfigurationProperty("", IsDefaultCollection = true)]
        [ConfigurationCollection(typeof(TemplateCollection), AddItemName = "template")]
        public TemplateCollection Templates
        {
            get
            {
                return base[""] as TemplateCollection;
            }
        }

        #endregion

    }

}
Run Code Online (Sandbox Code Playgroud)

这是下一个级别,集合类:

namespace formulate.app.Configuration
{

    // Namespaces.
    using System.Configuration;


    /// <summary>
    /// A collection of templates from the configuration.
    /// </summary>
    [ConfigurationCollection(typeof(TemplateElement))]
    public class TemplateCollection : ConfigurationElementCollection
    {

        #region Methods

        /// <summary>
        /// Creates a new template element.
        /// </summary>
        /// <returns>The template element.</returns>
        protected override ConfigurationElement CreateNewElement()
        {
            return new TemplateElement();
        }


        /// <summary>
        /// Gets the key for an element.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns>The key.</returns>
        protected override object GetElementKey(ConfigurationElement element)
        {
            return (element as TemplateElement).Name;
        }

        #endregion

    }

}
Run Code Online (Sandbox Code Playgroud)

这是最深层的类(各个模板):

namespace formulate.app.Configuration
{

    //  Namespaces.
    using System.Configuration;


    /// <summary>
    /// A "template" configuration element.
    /// </summary>
    public class TemplateElement : ConfigurationElement
    {

        #region Constants

        private const string DefaultPath = "~/*Replace Me*.cshtml";

        #endregion


        #region Properties

        /// <summary>
        /// The name of the template.
        /// </summary>
        [ConfigurationProperty("name", IsRequired = true)]
        public string Name
        {
            get
            {
                return base["name"] as string;
            }
            set
            {
                this["name"] = value;
            }
        }


        /// <summary>
        /// The path to this template.
        /// </summary>
        /// <remarks>
        /// Should start with "~" and end with ".cshtml".
        /// </remarks>
        [ConfigurationProperty("path", IsRequired = true, DefaultValue = DefaultPath)]
        [RegexStringValidator(@"^~.*\.[cC][sS][hH][tT][mM][lL]$")]
        public string Path
        {
            get
            {
                var result = base["path"] as string;
                return result == DefaultPath ? null : result;
            }
            set
            {
                this["path"] = value;
            }
        }

        #endregion

    }

}
Run Code Online (Sandbox Code Playgroud)

对我来说重要的一点是在 中包含空字符串ConfigurationPropertyAttribute并将 IsDefaultCollection 设置为 true。顺便说一下,我将配置放在一个外部文件中,如下所示:

<?xml version="1.0" encoding="utf-8" ?>
<templates>
    <template name="Responsive" path="~/Views/Formulate/Responsive.Bootstrap.Angular.cshtml" />
</templates>
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我的 web.config 看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <sectionGroup name="formulateConfiguration">
      <section name="templates" type="formulate.app.Configuration.TemplatesConfigSection, formulate.app" requirePermission="false"/>
    </sectionGroup>
  </configSections>
  <formulateConfiguration>
    <templates configSource="config\Formulate\templates.config"/>
  </formulateConfiguration>
</configuration>
Run Code Online (Sandbox Code Playgroud)

我想我会提到,以防其他人尝试将其添加到外部文件中(外部文件中的根级项目与 web.config 中的外部化元素相同,这有点不直观)。