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>
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!