Have you ever faced with need to have your custom configuration?

Probably yes, on MSDN you can find a good example on custom configuration here.
That example was not 100% what I need, since I needed few included one in others collections. Like below:

<?xml version=1.0 encoding=utf-8 ?>
<configuration>
  <configSections>
      <section name=ServicesSettings type=RoadMap.CustomConfiguration.ServicesSection, RoadMap.CustomConfiguration/>
  </configSections>
  <ServicesSettings>
    <Services>
      <add serviceName=Greeter isEnabled=true interval=7>
        <Messages>
          <add messageName=Hello/>
          <add messageName=World/>
        </Messages>
      </add>

      <add serviceName=BadBoy isEnabled=false interval=“10”>
        <Messages>
          <add messageName=Go to/>
          <add messageName=Hell/>
        </Messages>
      </add>

    </Services>
  </ServicesSettings>
</configuration>

As you see I want to get list of services which of them could be enabled or disabled also it could have interval to send one or many messages, which are also configured.

As you see I already added RoadMap.CustomConfiguration.ServicesSection to map ServiceSettings section to my appropriate class:

ServicesSection

using System.Configuration;
namespace RoadMap.CustomConfiguration
{
    public class ServicesSection : ConfigurationSection
    {
        [ConfigurationProperty(“Services”)]
        public ServicesCollection Services
        {
            get { return ((ServicesCollection)(base[“Services”])); }
        }
    }
}

Next you will probably will want to take a look is ServicesCollection:

ServicesCollection

using System.Configuration;
namespace RoadMap.CustomConfiguration
{
    [ConfigurationCollection(typeof(ServiceElement))]
    public class ServicesCollection : ConfigurationElementCollection
    {
        protected override ConfigurationElement CreateNewElement()
        {
            return new ServiceElement();
        }
        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((ServiceElement)(element)).Name;
        }
        public bool ContainsKey(string key)
        {
            var element = BaseGet(key);
            return element != null ? true : false;
        }
        public ServiceElement this[int idx]
        {
            get
            {
                return (ServiceElement)BaseGet(idx);
            }
        }
        public ServiceElement this[object key]
        {
            get
            {
                return (ServiceElement)BaseGet(key);
            }
        }
        public void Add(ServiceElement element)
        {
            base.BaseAdd(element);
        }
    }
}

ServiceElement

using System;
using System.Configuration;
namespace RoadMap.CustomConfiguration
{
    public class ServiceElement : ConfigurationElement
    {
        [ConfigurationProperty(“serviceName”, DefaultValue = “Greeter”, IsRequired = true)]
        [StringValidator(InvalidCharacters = “~!@#$%^&*()[]{}/;'”|\”, MinLength = 1, MaxLength = 60)]
        public String Name
        {
            get
            { return (String)this[“serviceName”]; }
            set
            { this[“serviceName”] = value; }
        }
        [ConfigurationProperty(“isEnabled”, DefaultValue = true, IsRequired = false)]
        public bool IsEnabled
        {
            get
            { return (bool)this[“isEnabled”]; }
            set
            { this[“isEnabled”] = value; }
        }
        [ConfigurationProperty(“interval”, DefaultValue = “10”, IsRequired = false)]
        [IntegerValidator(ExcludeRange = false, MaxValue = 100, MinValue = 1)]
        public int Interval
        {
            get
            { return (int)this[“interval”]; }
            set
            { this[“interval”] = value; }
        }
        [ConfigurationProperty(“Messages”)]
        public MessagesCollection Messages
        {
            get { return ((MessagesCollection)(base[“Messages”])); }
        }
    }
}

As you see it has Messages property which is again collection (similar to ServicesCollection) of MessageElements:

MessageElement

using System;
using System.Configuration;
namespace RoadMap.CustomConfiguration
{
    public class MessageElement : ConfigurationElement
    {
        [ConfigurationProperty(“messageName”, DefaultValue = “hi”, IsRequired = true)]
        [StringValidator(InvalidCharacters = “~!@#$%^&*()[]{}/;'”|\”, MinLength = 1, MaxLength = 60)]
        public String Name
        {
            get
            { return (String)this[“messageName”]; }
            set
            { this[“messageName”] = value; }
        }
    }
}

To ensure you that this works as expected just take a look on following screenshots:

We have one Greeter service:

It has two messages and second one is “World”:

Hope you could just copy-paste my code and also add MessagesCollection and you are done, just change naming to your needs.