Recently, I was needing to store information about 5 instances of an application server that I was accessing from my program. As I was entering the third set of values in <appSettings> section I decided to go a better route. What I wanted seemed simple: a section that worked exactly like the <connectionStrings> section, but with my own attributes. After several hours with the documentation and some on-line research, I got what I wanted. I was hoping it would only take 20-30 minutes. In order to provide you with the experience I hoped to have, I have written this post.
First, let show you what I wanted my section to look like:
<acmeConfiguration>
<add name="ERCOT"
connectionName="AcmeER" fileDir="\\server\path" baseUrl="http://server:9999" />
<add name="PM"
connectionName="AcmePM" fileDir="\\server2\path" baseUrl="http://serverxx:9901" />
</acmeConfiguration>
You will need to subclass three classes from System.Configuration namespace: ConfigurationSection, ConfigurationElementCollection, and ConfigurationElement which correspond to the <acmeConfiguration>, the set of elements within <acmeConfiguration>, and the <add> elements respectively. Understanding the above is the key to simplifying this exercise. Here’s the code that implements the section above:
public class AcmeConfigSection : ConfigurationSection {
[ConfigurationProperty("", IsRequired=true, IsDefaultCollection=true)]
public AcmeInstanceCollection Instances {
get { return (AcmeInstanceCollection) this[""]; }
set { this[""] = value; }
}
}
public class AcmeInstanceCollection : ConfigurationElementCollection {
protected override ConfigurationElement CreateNewElement() {
return new AcmeInstanceElement();
}
protected override object GetElementKey(ConfigurationElement element) {
return ((AcmeInstanceElement) element).Name;
}
}
public class AcmeInstanceElement : ConfigurationElement {
[ConfigurationProperty("name", IsKey=true, IsRequired=true)]
public string Name {
get { return (string) base["name"]; }
set { base["name"] = value; }
}
[ConfigurationProperty("connectionName", IsRequired=true)]
public string ConnectionName {
get { return (string)base["connectionName"]; }
set { base["connectionName"] = value; }
}
[ConfigurationProperty("fileDir", IsRequired = true)]
public string FileDir {
get { return (string)base["fileDir"]; }
set { base["fileDir"] = value; }
}
[ConfigurationProperty("baseUrl", IsRequired = true)]
public string BaseUrl {
get { return (string)base["baseUrl"]; }
set { base["baseUrl"] = value; }
}
}
Finally, for convenience, I created a class to provide static access to this collection similar to System.Configuration.ConfigurationManager.ConnectionStrings:
public class AcmeConfig {
protected static Dictionary<string, AcmeInstanceElement> _instances; static AcmeConfig() {
_instances = new Dictionary<string,AcmeInstanceElement>();
AcmeConfigSection sec = (AcmeConfigSection) System.Configuration.ConfigurationManager.GetSection("AcmeConfiguration");
foreach ( AcmeInstanceElement i in sec.Instances ) {
_instances.Add(i.Name, i);
}
} public static AcmeInstanceElement Instances(string instanceName) {
return _instances[instanceName];
}
private AcmeConfig() {
}
}
That’s it. I wish MS would put a sample like mine in the docs because I think this is what 99% of developers are looking for.
August 22, 2008 at 12:33 pm
Thanks for the useful information.
The logic they used for implementing this kind simple custom XML configuration seems a bit too complex don’t you think?
Also whats the deal with
this[“”]
I also didn’t notice that i needed to make the collection items “Add” items. I at first tried to implement my own name for these nodes.
Thanks again for the good resource – it saved me some time!
February 1, 2011 at 3:12 am
Hmm Microsoft do have a example on MSDN, but it’s written as you say in a contrived way, there are some good tips in there, but the MSDN sample it just not useable in a non-trivial application because it suffers from the “copy-paste” defect all over the place.
Good work John
August 28, 2011 at 6:06 am
Code formatting man, code formatting
Otherwise very useful post
January 19, 2012 at 5:41 pm
Instead of using Dictionary how would you create a List. For a custom config section like this:
<add name="ERCOT"
<add name="PM"
January 24, 2012 at 7:19 pm
This is EXACTLY what I wanted. This has saved me hours of time at work. Thanks for the lesson :D
June 5, 2012 at 3:12 pm
[…] Today I found the need to create a custom section in Web.config. Being quite a while since last time I did this, I spent some time googling around until I found this blogpost from 2007: Custom ConfigurationSections in .NET 2.0 .config Files […]
June 13, 2012 at 4:15 am
Seems to have stripped out the xml, trying again
<section name="serviceConfiguration" type="ConsoleApplication1.ServiceConfigSection, ConsoleApplication1"
June 14, 2012 at 5:12 am
thanks, john. this really helped!
June 25, 2012 at 4:54 am
Thanks.
June 27, 2012 at 2:13 pm
Why can’t the MS examples be this simple?
Thanks
July 3, 2012 at 12:27 am
[…] https://jopinblog.wordpress.com/2007/04/20/custom-configurationsections-in-net-20-config-files/ […]
November 15, 2012 at 4:38 pm
Thanks! Great post, really neat example, saved me a lot of time!
July 8, 2013 at 2:11 pm
I’m having problem in the following line
AcmeConfigSection sec = (AcmeConfigSection)System.Configuration.ConfigurationManager.GetSection(“acmeConfiguration”);
The ‘sec’ object is showing up as null in runtime.
This is the app.config I’m using.
Also, one more question – Is there any reason why following is an empty string instead of ‘acmeConfiguration’
public class AcmeConfigSection : ConfigurationSection
{
[ConfigurationProperty(“”, IsRequired = true, IsDefaultCollection = true)]
public AcmeInstanceCollection Instances
{
get { return (AcmeInstanceCollection)this[“”]; }
set { this[“”] = value; }
}
}
July 8, 2013 at 2:12 pm
Sorry, reposting with the app.config
February 9, 2016 at 7:11 am
Thank you so much John. Just a small question .. Don’t we need to add this newly created section in ConfigSections and define the type there ?
February 9, 2016 at 7:49 am
Yes, that’s correct.