none
Custom config polymorphic nested elements RRS feed

  • Question

  • I've got a problem with creating polymorphic nested elements. Here is my config:
    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <configSections>
            <section name="Section1" type="Tools.Section, Tools"/>
        </configSections>
        <Section1 file_name="Data_file">
            <Collection>
                <Element name="Element1" param_name="param_value">
                    <Subelement1 SubElement1_type="SomeSubElement1" sub_param_name1="1"/>
                    <Subelement2 SubElement2_type="SomeSubElement2" sub_param_name2="2"/>
                </Element>          
            </Collection>
        </Section1> 
    <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/></startup>
    </configuration>

    I don't want to use element collection inside the base element, because there can be only two subelements.

    First i have to mention that there always should exist subelement1 and subelement2, but they have to be polymorphic as number of parameters may vary. Here is the code i have now:
    public class BaseSubElement1 : ConfigurationElement
    {
        [ConfigurationProperty("SubElement1_type", IsRequired = false, IsKey = true, DefaultValue = "")]
        [StringValidator(InvalidCharacters = "  ~!@#$%^&*()[]{}/,;’\"|\\")]
        public string SubElement1_type
        {
            get { return (string)this["SubElement1_type"]; }
        }
    }
    
    public class SomeSubElement1 : BaseSubElement1
    {
        [ConfigurationProperty("sub_param_name1", IsRequired = false, DefaultValue = 0.0)]
        public double sub_param_name1
        {
            get { return (double)this["sub_param_name1"]; }
        }
    }
    
    public class BaseSubElement2 : ConfigurationElement
    {
        [ConfigurationProperty("SubElement2_type", IsRequired = false, IsKey = true, DefaultValue = "")]
        [StringValidator(InvalidCharacters = "  ~!@#$%^&*()[]{}/,;’\"|\\")]
        public string SubElement2_type
        {
            get { return (string)this["SubElement2_type"]; }
        }
    }
    
    public class SomeSubElement2 : BaseSubElement2
    {
        [ConfigurationProperty("sub_param_name2", IsRequired = false, DefaultValue = 0.0)]
        public double sub_param_name2
        {
            get { return (double)this["sub_param_name2"]; }
        }
    }
    
    public class Element : ConfigurationElement
    {
        [ConfigurationProperty("param_name", IsRequired = true, IsKey = true, DefaultValue = "")]
        [StringValidator(InvalidCharacters = "  ~!@#$%^&*()[]{}/,;’\"|\\")]
        public string param_name
        {
            get { return (string)this["param_name"]; }
        }
    
        [ConfigurationProperty("SubElement1", IsRequired = true, DefaultValue = null)]
        public BaseSubElement1 SubElement1
        {
            get
            {
                switch (SubElement1_type) //how do get SubElement1_type here?
                {
                    case "SomeSubElement1": return new SomeSubElement1();
                    default: break;
                }
            }
        }
    
        [ConfigurationProperty("SubElement2", IsRequired = true, DefaultValue = null)]
        public BaseSubElement2 SubElement2
        {
            get
            {
                switch (SubElement2_type) //how do get SubElement2_type here?
                {
                    case "SomeSubElement2": return new SomeSubElement2();
                    default: break;
                }
            }
        }
    }
    
    [ConfigurationCollection(typeof(BaseStrategyElement), CollectionType = ConfigurationElementCollectionType.BasicMap)]
    public class ElementCollection : ConfigurationElementCollection
    {
        protected override ConfigurationElement CreateNewElement()
        {
            // Not used but function must be defined
            return null;
        }
    
        protected override object GetElementKey(ConfigurationElement element)
        {
            return element;
        }
    
        protected override ConfigurationElement CreateNewElement(string elementName)
        {
            return new Element();
        }
    
        protected override bool IsElementName(string elementName)
        {
            // Required to be true
            return true;
        }
    
        public override ConfigurationElementCollectionType CollectionType
        {
            get { return ConfigurationElementCollectionType.BasicMap; }
        }
    }
    
    public class Section : ConfigurationSection
    {
        [ConfigurationProperty("file_name", IsRequired = false, DefaultValue = "")]
        [StringValidator(InvalidCharacters = "\\/:*?<>\"|")]
        public string file_name
        {
            get { return (string)this["file_name"]; }
        }
    
        [ConfigurationProperty("Collection")]
        public ElementCollection Collection
        {
            get { return (ElementCollection)this["Collection"]; }
        }
    }

    And here is how i access the config:
    ExeConfigurationFileMap map = new ExeConfigurationFileMap();
    map.ExeConfigFilename = "app.config";
    Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
    IEnumerable<Section> section_collection = config.Sections.OfType<Section>();
    
    foreach (Section section in section_collection)
    {
        //do some work with sections
    }

    So i have the problem with getting `SubElement1_type` and `SubElement2_type` because Subelement1 and Subelement2 are not created yet and i can't access their properties.

    Also i tried to move subelement types to element properties.
    <Element name="Element1" param_name="param_value" SubElement1_type="SomeSubElement1" SubElement2_type="SomeSubElement2">
        <Subelement1 sub_param_name1="1"/>
        <Subelement2 sub_param_name2="2"/>
    </Element>

    Now handling code is:

    public class Element : ConfigurationElement
    {
        [ConfigurationProperty("param_name", IsRequired = true, IsKey = true, DefaultValue = "")]
        [StringValidator(InvalidCharacters = "  ~!@#$%^&*()[]{}/,;’\"|\\")]
        public string param_name
        {
            get { return (string)this["param_name"]; }
        }
    
        [ConfigurationProperty("SubElement1_type", IsRequired = false, IsKey = true, DefaultValue = "")]
        [StringValidator(InvalidCharacters = "  ~!@#$%^&*()[]{}/,;’\"|\\")]
        public string SubElement1_type
        {
            get { return (string)this["SubElement1_type"]; }
        }
    
        [ConfigurationProperty("SubElement2_type", IsRequired = false, IsKey = true, DefaultValue = "")]
        [StringValidator(InvalidCharacters = "  ~!@#$%^&*()[]{}/,;’\"|\\")]
        public string SubElement2_type
        {
            get { return (string)this["SubElement2_type"]; }
        }
    
        [ConfigurationProperty("SubElement1", IsRequired = true, DefaultValue = null)]
        public BaseSubElement1 SubElement1
        {
            get
            {
    
                switch (this["SubElement1_type"]) //here this["SubElement1_type"] is empty
                {
                    case "SomeSubElement1": return new SomeSubElement1();
                    default: break;
                }
            }
        }
    
        [ConfigurationProperty("SubElement2", IsRequired = true, DefaultValue = null)]
        public BaseSubElement2 SubElement2
        {
            get
            {
                switch (this["SubElement2_type"]) //here this["SubElement2_type"] is empty
                {
                    case "SomeSubElement2": return new SomeSubElement2();
                    default: break;
                }
            }
        }
    }

    But when i try to get the subelement type, it is empty at runtime.
    Thursday, December 4, 2014 3:41 PM

All replies

  • Check this link:

    http://msdn.microsoft.com/en-us/library/system.configuration.configurationelement(v=vs.110).aspx

    It shows how to customize config polymorphic nested elements.                               

    Friday, December 5, 2014 8:55 AM
  • Sure i've seen it. And i don't really understand how can it help me. Maybe i missed something?

    The problem i have is that creation of elements goes recursively from the deepest level as i understand. And when the subelement is created in the element (first case) or in the collection (second case), subelement_type is undefined yet. And i don't know how to overcome it.

    Monday, December 8, 2014 3:01 PM
  • Hello paulbir,

    For this issue, I am trying to invoke someone experienced to help look into this thread, this may take some time and as soon as we get any result, we will post back.

    Regards.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Wednesday, December 10, 2014 10:00 AM
    Moderator