Yesterday afternoon and the early bits of this morning I spent my time breaking my head on creating a custom ConfigurationSection. I kept getting an exception with the message unrecognized element ‘add’. I thought it would all be so simple!
Here’s the background of why I ended up tinkering with this stuff. I wanted to define a few custom tags in my web.config to specify which modules should be loaded when the application would start. A quick google search learned me that creating my own custom ConfigurationSection was the way to go. It didn’t look too difficult, so I got right down to business and started coding away!
Web.config:
<configSections>
<sectionGroup name="moduleSettings">
<section
name="modules"
type="Storminajar.Modules.Framework.Configuration
.ModuleSection,
Storminajar.Modules.Framework"
allowDefinition="Everywhere"
allowLocation="true"/>
</sectionGroup>
</configSections>
<moduleSettings>
<modules>
<module name="Module 1"
description="My first module!"
type="Storminajar.Modules.Module1.MyModule,
Storminajar.Modules.Module1" />
<module name="Module 2"
description="My second module!"
type="Storminajar.Modules.Module2.MyModule,
Storminajar.Modules.Module2" />
</modules>
</moduleSettings>
Let’s have a look at the working code.
ConfigurationSection:
public class ModuleSection : ConfigurationSection
{
[ConfigurationProperty("", IsDefaultCollection = true)]
[ConfigurationCollection(typeof(ModuleCollection),
AddItemName="module")]
public ModuleCollection Modules
{
get { return (ModuleCollection)this[""]; }
set { this[""] = value; }
}
}
ConfigurationElementCollection:
public class ModuleCollection : ConfigurationElementCollection
{
public ModuleCollection()
{
}
#region ConfigurationElementCollection Specific Memebers
protected override ConfigurationElement CreateNewElement()
{
return new ModuleElement();
}
protected override object GetElementKey(
ConfigurationElement element)
{
return ((ModuleElement)element).Name;
}
public override ConfigurationElementCollectionType
CollectionType
{
get
{
return ConfigurationElementCollectionType
.AddRemoveClearMap;
}
}
#endregion
#region Collection Related Members
public ModuleElement this[int index]
{
get { return (ModuleElement)BaseGet(index); }
set
{
if (BaseGet(index) != null)
{
BaseRemoveAt(index);
}
BaseAdd(value);
}
}
public new ModuleElement this[string cultureKey]
{
get { return (ModuleElement)BaseGet(cultureKey); }
set
{
if (BaseGet(cultureKey) != null)
{
BaseRemove(cultureKey);
}
BaseAdd(value);
}
}
public bool Contains(string name)
{
foreach (ModuleElement element in this)
{
if (element.Name == name)
{
return true;
}
}
return false;
}
public void Add(ModuleElement element)
{
BaseAdd(element, true);
}
public int IndexOf(ModuleElement element)
{
return BaseIndexOf(element);
}
public void RemoveAt(int index)
{
if (this.Count > index)
{
BaseRemoveAt(index);
}
}
public void Remove(ModuleElement element)
{
if (BaseIndexOf(element) >= 0)
{
RemoveAt(BaseIndexOf(element));
}
}
public void Clear()
{
BaseClear();
}
#endregion
}
ConfigurationElement:
public class ModuleElement : ConfigurationElement
{
[ConfigurationProperty("name", IsRequired = true)]
public string Name
{
get
{
return this["name"] as string;
}
}
[ConfigurationProperty("description", IsRequired = false)]
public string Description
{
get
{
return this["description"] as string;
}
}
[ConfigurationProperty("type", IsRequired = false)]
public string Type
{
get
{
return this["type"] as string;
}
}
}
If you ever get to the point of banging your head on your desk, because of the aforementioned unrecognized element ‘add’, make sure to double check the implementation of the ConfigurationSection! It’s extremely important to have defined the ConfigurationProperty with an empty string! It only seems to occur when a value is specified at this point!
[ConfigurationProperty("", IsDefaultCollection = true)]
[ConfigurationCollection(typeof(ModuleCollection),
AddItemName="module")]
public ModuleCollection Modules { ... }
Let me repeat that:
It’s extremely important to have defined the ConfigurationProperty of the ConfigurationElementCollection in the ConfigurationSection with an empty string!
I spent a couple of hours trying to figure this out… A bit of a waste of time!