Search code examples
c#custom-configuration

How do I make my custom config section behave like a collection?


How would I need to write my custom ConfigurationSection so that it is both a section handler and a configuration element collection?

Normally, you have one class that inherits from ConfigurationSection, which then has a property that is of a type that inherits from ConfigurationElementCollection, which then returns elements of a collection of a type that inherits from ConfigurationElement. To configure that, you would then need XML that looks something like this:

<customSection>
  <collection>
    <element name="A" />
    <element name="B" />
    <element name="C" />
  </collection>
</customSection>

I want to cut out the <collection> node, and just have:

<customSection>
  <element name="A" />
  <element name="B" />
  <element name="C" />
<customSection>

Solution

  • I assume that the collection is a property of your custom ConfigurationSection class.

    You can decorate this property with the following attributes:

    [ConfigurationProperty("", IsDefaultCollection = true)]
    [ConfigurationCollection(typeof(MyElementCollection), AddItemName = "element")]
    

    A full implementation for your example could look like this:

    public class MyCustomSection : ConfigurationSection
    {
        [ConfigurationProperty("", IsDefaultCollection = true)]
        [ConfigurationCollection(typeof(MyElementCollection), AddItemName = "element")]
        public MyElementCollection Elements
        {
            get { return (MyElementCollection)this[""]; }
        }
    }
    
    public class MyElementCollection : ConfigurationElementCollection, IEnumerable<MyElement>
    {
        private readonly List<MyElement> elements;
    
        public MyElementCollection()
        {
            this.elements = new List<MyElement>();
        }
    
        protected override ConfigurationElement CreateNewElement()
        {
            var element = new MyElement();
            this.elements.Add(element);
            return element;
        }
    
        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((MyElement)element).Name;
        }
    
        public new IEnumerator<MyElement> GetEnumerator()
        {
            return this.elements.GetEnumerator();
        }
    }
    
    public class MyElement : ConfigurationElement
    {
        [ConfigurationProperty("name", IsKey = true, IsRequired = true)]
        public string Name
        {
            get { return (string)this["name"]; }
        }
    }
    

    Now you can access your settings like this:

    var config = (MyCustomSection)ConfigurationManager.GetSection("customSection");
    
    foreach (MyElement el in config.Elements)
    {
        Console.WriteLine(el.Name);
    }
    

    This will allow the following configuration section:

    <customSection>
        <element name="A" />
        <element name="B" />
        <element name="C" />
    <customSection>