Search code examples
c#web-configconfigurationsection

How to have a collection of configuration sections in a .config file


I want to be able to use the following setup in my app/web.config files:

<listeners>
    <listener type="a">
         <parameter name="a", value="2" />
         <parameter name="b", value="20" />
    </listener>
    <listener type="b">
         <parameter name="a", value="2" />
         <parameter name="b", value="20" />
         <parameter name="c", value="200" />
    </listener>
    ...
</listeners>

Basically, I want to represent a collection of listeners, where each listener has several attributes as well as a collection of parameters. I've managed to model the listener element as a ConfigurationSection with the parameters as ConfigurationElements. However, I can't find an example of how to create the outer collection of listeners. What do I need to do to model this?

I tried making listeners a ConfigurationSectionGroup but this failed at runtime because it seems like the group can't have multiple sections of the same name.


Solution

  • It might be a cop-out since this doesn't use any custom handlers, but you could use an arbitrary XML section in conjunction with an XmlSerializer.

      <section name="listeners" type="System.Configuration.DefaultSection" />
      ...
    
    <listeners>
      <listener type="a">
        <parameter name="a" value="2" />
        <parameter name="b" value="20" />
      </listener>
      <listener type="a">
        <parameter name="a" value="2" />
        <parameter name="b" value="20" />
        <parameter name="c" value="200" />
      </listener>
    </listeners>
    

    To obtain the array of listeners, get the raw XML and deserialize it if you want objects.

    The serializable classes:

    public class Parameter
    {
        [XmlAttribute("name")]
        public String Name { get; set; }
        [XmlAttribute("value")]
        public Int32 Value { get; set; }
    }
    
    [XmlType(TypeName = "listener")]
    public class Listener
    {
        [XmlAttribute("type")]
        public String Type { get; set; }
    
        [XmlElement("parameter")]
        public Parameter[] Parameters;
    }
    

    And, the operation itself:

    var serializer = new XmlSerializer(typeof(Listener[]), 
                                       new XmlRootAttribute("listeners"));
    var configuration = ConfigurationManager
        .OpenExeConfiguration(ConfigurationUserLevel.None);
    var section = configuration.GetSection("listeners");
    var rawXml = section.SectionInformation.GetRawXml();
    using (var stringReader = new StringReader(rawXml))
    {
        var listeners = (Listener[])serializer.Deserialize(stringReader);
    }
    

    (Or, instead of XmlSerializer, you could use XDocument to parse the XML and peek at individual elements or attributes.)