Search code examples
.netcustom-configuration

Polymorphic custom configuration section


Lets say I have the following configuration section....

<yak>
    <whaa hello="world" />
</yak>
<yak>
   <whaa hello="world" blot="1" />
</yak>

Because the second <whaa> element has the extra attribute on it I want to map it to a sub type of the the type that's mapped to the first <whaa> element.

So how do I get polymorphic binding?


Solution

  • Here's one approach by using a programmatic solution which overrides the OnDeserializeUnrecognizedElement method of the ConfigurationSection class. The base and child configuration element classes:

    public class Whaa : ConfigurationElement
    {
        [ConfigurationProperty("hello", IsRequired = true)]
        public string Hello
        {
            get
            {
                return base["hello"] as string;
            }
            set
            {
                base["hello"] = value;
            }
        }
    }
    
    public class WhaaChild : Whaa
    {
        [ConfigurationProperty("blot", IsRequired = true)]
        public string Blot
        {
            get
            {
                return base["blot"] as string;
            }
            set
            {
                base["blot"] = value;
            }
        }
    }
    

    The configuration section class:

    public class Yak : ConfigurationSection
    {
        public Whaa MyProperty;
    
        protected override bool
            OnDeserializeUnrecognizedElement(string elementName, XmlReader reader)
        {
            if (elementName == "whaa")
            {
                try
                {
                    var hello = reader.GetAttribute("hello");
                    if (hello != null)
                    {
                        var blot = reader.GetAttribute("blot");
                        if (blot != null)
                        {
                            MyProperty = new WhaaChild()
                            {
                                Blot = blot,
                                Hello = hello
                            };
                        }
                        else
                        {
                            MyProperty = new Whaa()
                            {
                                Hello = hello
                            };
                        }
                    }
                }
                catch (Exception)
                {
                    // TODO: add exception handling
                }
            }
            return true;
        }
    }
    

    The sample usage:

    var yakSectionSettings = (Yak)ConfigurationManager.GetSection("yak");
    

    And the configuration markup:

    <configSections>
        <section name="yak" type="Yak, MyApplication"/>
    </configSections>
    

    You may use now either:

    <yak>
        <whaa hello="world"/>
    </yak>
    

    for getting a Whaa object, or:

    <yak>
        <whaa hello="world" blot="1"/>
    </yak>
    

    for getting a WhaaChild object at runtime.