IConfigurationSectionHandler Is Dead! Long Live IConfigurationSectionHandler!
I was tasked to create the configuration functionality of the architectural components for an SOA project that I previously worked on. I took as much time as I can in designing the XML thinking that it will be very easy to process it and churn it into a Configuration class by implementing the IConfigurationSectionHandler interface. And just when I started to develop it, I found out that the IConfigurationSectionHandler interface has been deprecated in .Net 2.0.
I’m the type of guy who is OC about this kind of stuff. And so I head forth to find out a solution. The page in MSDN for the interface says that.
In .NET Framework version 2.0 and above, you must instead derive from the ConfigurationSection class to implement the related configuration section handler.
Digging deeper, I learned that they have moved on to a more declarative way of processing configuration sections. So what used to be a series of xml manipulations is now a bunch of configuration classes decorated with the necessary attributes.
In this article, I will try to cover the necessary steps in creating a ConfigurationSection using the .Net 2.0 configuration classes.
The Mark-Up
When creating .Net configurations, I normally start with the xml markup to use. For the purpose of illustration, let’s just say I want to save a list of users and be able to read it at runtime.
1 <?xml version="1.0" encoding="utf-8" ?>
2 <configuration>
3 <configSections>
4 <section name="project-configuration"
5 type="NewConfigurationSection.ProjectConfigurationSection,
6 NewConfigurationSection"/>
7 </configSections>
8 <project-configuration>
9 <users>
10 <add key="jakelite" firstname="jake" lastname="sta teresa" />
11 <add key="pinoy" firstname="juan" lastname="dela cruz" />
12 <add key="kano" firstname="uncle sam" lastname="lagmay" />
13 </users>
14 </project-configuration>
15 </configuration>
The UserElement
The elements inside the users' node should map to a ConfigurationElement class. Each attribute in the configuration xml will map to a property decorated with a ConfigurationPropertyAttribute.
1 internal class UserElement : ConfigurationElement
2 {
3 public UserElement()
4 {
5 }
6
7 public UserElement(string key)
8 {
9 Key = key;
10 }
11
12 [ConfigurationProperty("key", IsRequired = true, IsKey = true)]
13 public string Key
14 {
15 get { return (string)(base["key"]); }
16 set { base["key"] = value; }
17 }
18
19 [ConfigurationProperty("firstname", IsRequired = true)]
20 public string Firstname
21 {
22 get { return (string)(base["firstname"]); }
23 set { base["firstname"] = value; }
24 }
25
26 [ConfigurationProperty("lastname", IsRequired = true)]
27 public string Lastname
28 {
29 get { return (string)(base["lastname"]); }
30 set { base["lastname"] = value; }
31 }
32 }
The UserElementCollection
The users' node should map to a ConfigurationElementCollection class. I find this to be the hardest part in doing this so I created a generic class called ConfigurationElementCollection<T>. The collection should be decorated with a ConfigurationCollectionAttribute specifying the type of ConfigurationElement is contains.
1 [ConfigurationCollection(typeof(UserElement),
2 CollectionType = ConfigurationElementCollectionType.BasicMap)]
3 internal sealed class UserElementCollection :
4 ConfigurationElementCollection<UserElement>
5 {
6 }
The ConfigurationSection
As advised in the MSDN article, we should create a class that inherits from ConfigurationSection instead of the now deprecated IConfigurationSectionHandler interface. You will find the configuration section class below.
1 public sealed class ProjectConfigurationSection :
2 ConfigurationSection
3 {
4 [ConfigurationProperty("users",
5 IsDefaultCollection = true, IsRequired = true)]
6 internal UserElementCollection Users
7 {
8 get { return (UserElementCollection)this["users"]; }
9 }
10 }
Retrieving The Users
To retrieve the users contained in the configuration, you will have to open the configuration, then locate the configuration section of the target type. Then you can cast it to the target type and use the class in a strongly typed manner. This allows you to access the child nodes as properties.
1 Configuration configuration =
2 ConfigurationManager.OpenExeConfiguration(
3 ConfigurationUserLevel.None);
4 ProjectConfigurationSection configurationSection = null;
5 ConfigurationSectionCollection sections = configuration.Sections;
6 foreach (ConfigurationSection section in sections)
7 {
8 if (section is ProjectConfigurationSection)
9 {
10 configurationSection = section
11 as ProjectConfigurationSection;
12 break;
13 }
14 }
15
16 if (configurationSection != null)
17 {
18 Console.WriteLine("Configured Users");
19 foreach (UserElement user in configurationSection.Users)
20 {
21 Console.WriteLine("User {0}: {1} {2}",
22 user.Key,
23 user.Firstname,
24 user.Lastname);
25 }
26 Console.ReadKey(false);
27 }
Final Words
In this article we looked at the new way of accessing .Net configuration. This new approach offers a more declarative/OO way of accessing configuration.
However, the sheer verbosity of the new programming model is quite tedious. Add to that the lack of proper samples in the documentation; particularly when implementing ConfigurationElementCollections.
In the end, you will have to choose the new approach if you want to future proof your application configuration strategy. But as for me, I’d trade it anytime to get back IConfigurationSectionHandler.
Code for the samples can be found here.