Search code examples
.netconfigurationapp-configconfigurationsectionconfigurationelement

How do I use .NET custom ConfigurationElement properties on descendent elements?


How can I get and use an attribute set in the parent ConfigurationSection in the descendent CustomSetting element? I need this attribute when the CustomSetting element is returning the Value property.

I want to format the App.config like this:

<CustomSettings someProperty="foo">
    <CustomSetting key="bar" value="fermeneba" />
    <CustomSetting key="laa" value="jubaduba" />
</CustomSettings>

I have the code working, except that I cannot find a way to access the someProperty attribute from the CustomSetting class. The only way that I've found, so far, is to format the configuration like this, which is messy:

<CustomSettings>
    <CustomSetting someProperty="foo" key="bar" value="fermeneba" />
    <CustomSetting someProperty="foo" key="laa" value="jubaduba" />
</CustomSettings>

Solution

  • Achieving this is more difficult than it should be since the System.Configuration API doesn't allow you to navigate from a ConfigurationElement to its parent. Hence, if you want to access some information that on a parent element you need to create that relationship manually. I've put together a sample implementation that does that for the config snippet in your question:

    public class CustomSettingsSection : ConfigurationSection
    {
        [ConfigurationProperty("someProperty", DefaultValue="")]
        public string SomeProperty
        {
            get { return (string)base["someProperty"]; }
            set { base["someProperty"] = value; }
        }
    
        [ConfigurationProperty("", IsDefaultCollection = true)]
        public CustomSettingElementCollection Elements
        {
            get 
            {
                var elements = base[""] as CustomSettingElementCollection;
                if (elements != null && elements.Section == null)
                    elements.Section = this;
                return elements;
            }
        }
    }
    
    public class CustomSettingElementCollection : ConfigurationElementCollection
    {
    
        internal CustomSettingsSection Section { get; set; }
    
        public override ConfigurationElementCollectionType CollectionType
        {
            get { return ConfigurationElementCollectionType.BasicMap; }
        }
    
        public CustomSettingElement this[string key]
        {
            get { return BaseGet(key) as CustomSettingElement; }
        }
    
        protected override ConfigurationElement CreateNewElement()
        {
            return new CustomSettingElement { Parent = this };
        }
    
        protected override object GetElementKey(ConfigurationElement element)
        {
            return (element as CustomSettingElement).Key;
        }
    
        protected override string ElementName
        {
            get { return "customSetting"; }
        }
    }
    
    public class CustomSettingElement : ConfigurationElement
    {
    
        internal CustomSettingElementCollection Parent { get; set; }
    
        public string SomeProperty
        {
            get
            {
                if (Parent != null && Parent.Section != null)
                    return Parent.Section.SomeProperty;
                return default(string);
            }
        }
    
    
    
    
        [ConfigurationProperty("key", IsKey = true, IsRequired = true)]
        public string Key
        {
            get { return (string)base["key"]; }
            set { base["key"] = value; }
        }
    
        [ConfigurationProperty("value", DefaultValue = "")]
        public string Value
        {
            get { return (string)base["value"]; }
            set { base["value"] = value; }
        }
    
    }
    

    You can see that the CustomSettingElementCollection has a Section property which gets set in the section's Elements getter. The CustomSettingElement, in turn, has a Parent property which gets set in the collection's CreateNewElement() method.

    That then makes it possible to walk up the relationship tree and to add a SomeProperty property to the element even though this one doesn't correspond to an actual ConfigurationProperty on that element.

    Hope that gives you an idea how to solve your problem!