16

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>
theBoringCoder
  • 233
  • 2
  • 14
  • Could you please consider changing the title of your question to be more specific? I suggest something like "How do I make my custom config section behave like a collection?" or something along those lines. This would automatically remove the "C#" from the question title which is unnecessary because you already tagged the question with it. – julealgon May 07 '15 at 14:29
  • When you ask the actual question, you will soon realize that it's quite possible that someone has asked it already. [This one](http://stackoverflow.com/questions/6379110/custom-config-section-containing-collection) could be a duplicate of your question, for example. – julealgon May 07 '15 at 14:31

1 Answers1

24

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>
Sébastien Sevrin
  • 5,267
  • 2
  • 22
  • 39
Elian Ebbing
  • 18,779
  • 5
  • 48
  • 56
  • You have three classes in your example. I know that's the way Microsoft shows us how to do it...but that means your XML will have three levels: the section, the collection, the elements in the collection. I want to do it with two: the section, the elements in section (as if the section were also a colelction). – theBoringCoder Jan 17 '13 at 23:21
  • 3
    @theBoringCoder You indeed have still three levels in your classes, but this example uses exactly the example that you wanted. The `MyElementCollection` class does not translate to an xml element. – Elian Ebbing Jan 18 '13 at 12:22
  • 3
    @theBoringCoder Wow, that's some delayed response :) – Elian Ebbing Apr 21 '13 at 22:45