This post will provide an example and explanation of how to create custom configuration for C# applications. I will discuss ConfigurationSections, ConfigurationElements, ConfigurationElementCollection. Also I will discuss how to nest these items together. My plan is to take very small steps; implementing each part of the configuration individually.
By the end of the post we will be able to navigate a custom configuration similar to the following config file:
Assumption
- Good understanding of C#
- Good understanding Visual Studio – I’m will be using VS 2012
- .NET 3.5 and higher
-
Basic understanding of configuration files
The application we are going to create is quite contrived. The school settings that we will store in the config file would usually be stored in a database, but I want to provide a domain that most people understand.
Our Domain
We are going to create a Windows Console application. All it’s going to do is display values from the config file. When we are completed with the application it will display something similar to this:
-
Create Console Application called SchoolBlog.
-
Add Reference to System.Configuration
-
Add the System.Config namespace to the program.cs file
-
Access the Configuration
Add the following code (see image below)
This code attempts to access Configuration Section in the config file called “school” and cast the results to a type of “SchoolConfig”. This will not compile or run since we don’t have a Configuration Section in the config file called “school” and we do not have a class call “SchoolConfif”. We will solve this in the following steps.
-
Create SchoolConfig Class
I made my SchoolBlog class public
-
Inherit from Class ConfigurationSection
I added the “using System.Configuration” to the SchoolBlog.cs file
Have SchoolConfig inherit from ConfigurationSection.
-
In App.Config File, Reference the SchoolBlog.SchoolConfig Class
A first this image may be somewhat confusing, but I believe it’s very beneficial in helping to understand how the different configuration part of the application relates to each other.
The above image has three parts. The top part is the “Program” class that references the “school” section in the config file. The middle part is the app.config file. The bottom part is our SchoolConfig class that we create in the previous step.
In the image you should notice that the text “school” is tightly couple between the Program, the configSection and the “<school>” xml. In steps below we will remove the tight coupling between Program class and the other parts of the configuration, but for now this will work.
In the app.config file I added a “configSection” and a schoolSection. The configSection is used to identify where configuration class is located. This would be the class that inherits from ConfigurationSection. In our example the configuration class is located in our SchoolBlog application (assembly). But if you were using or creating a 3rd party component, the configuration class would probably be located in a dll (assembly) external to your application.
The <configSections> has a <section> with the name=”school”. The name “school” matches the GetSection(“school’) and the “<school>” xml. The “type” identifies the location of the class that inherits from “ConfigurationSection”. In our case, the class that we are looking for is in the namespace “SchoolBlog, and in the class “SchoolConfig”. This is located in the assembly SchoolBlog. For us the namespace “SchoolBlog” and assembly “SchoolBlog” coincidnence; many times this will be true, but not always.
-
Sanity Check
Now run the application. Nothing spectacular should happen. But if you don’t get any errors, then everything should be coded correctly.
Before you move onto the next step, make sure this is working without any errors.
-
Get School Name
In the image above there are 3 parts. This pattern will continue through the rest of the post. The top part is the “Program” class. The middle part is the <school> XML that will contain the configuration data. The bottom part is the “SchoolConfig” class that is used to retrieve configuration data from the XML in the app.config file.
In the “Program” class we want to be able to retrieve the name of the school.
In the XML configuration we add the attribute name to the “<school>” element with the value of “South High”.
In the “SchoolBlog” class we add a ConfigurationProperty attribute with the value “name”. We also create a property called “Name” that return a base value for “name”. It’s important to notice the difference cases-sensitivity for “Name”. If you noticed in XML that “name” is lower case. This follows the convention for naming XML attribute. Bus also notice that property “Name” is uppercase; this following the convention for naming C# public properties.
-
Sanity Check
Now run the application. The School Name should be displayed.
Before you move onto the next step, make sure this is working without any errors.
-
Refactoring
Lets move the “ConfigurationManager.GetSection(“school”)” to SchoolBlog class.
In this step we move the process that access of the configuration from the “Program” class to the “SchoolConfig” class. This simplify the “Program” class. Now when we want to access configuration data we can use “SchoolConfig.Settings”
-
School Address
In the “Program” class we get values for street, city, and state values for address.
The XML configuration data now contains an element call address with multiple attributes (street, city, and state)
Om the “SchoolConfig” I added 2 new parts. The first is the new ConfigurationProperty “address”. The second is the new class “AddressElement”.
We will first discuss the new “AddressElement” class. If you notice, the “<address>” XML in the app.config is a new element. So, the new XML element needs a new class that inherits from “ConfigurationElement”. So we created a new class called “AddressElement” that inherits from “ConfigurationElement”. This class has three new properties (Street, City, State). Notice that each C# property name (Street, City, State) is uppercase, but when referencing each the XML attribute they are lowercase. This is very similar to the “Name” property that we created for the “SchoolConfig” class.
Since “<school>” XML contains the element “<address>”, we will add a new property to the “SchoolConfig” class of type “AddressElement”. Notice here that that C# property is uppercase and the “address” strings are lowercase.
-
Sanity Check
Now run the application. The Address should be displayed.
Before you move onto the next step, make sure this is working without any errors.
-
Individual Course
I never know which to present first the collection of elements, or the elements themselves. Since the “CourseElementCollection” class depends on CourseElement class, I believe we will look at individual course element first (CourseElement).
In the “<school>” XML we added the element called “<courses>”. “<courses>” is an element that can contain zero or more “<course>” elements. Each “<course>” element has the attributes “title” and “instructor”. The “title” attribute is required. The “instructor” attribute is not required.
The “CourseElement” class inherits from “ConfigurationElement”. The “CouseElement” class is very similar to the other ?Element classes that we created earlier. Even though I will not go into detail about the “CourseElement” class, do note that the “IsRequired” property for each “ConfigurationProperty” attribute. One is set to true and the other is set to false.
-
Collection of Courses
Here we will create the code that allows us to work with collection of course. I won’t go over all this code, but I will try to highlight the main sections.
First there is a C# attribute “ConfigurationCollection”. This has many different parameters. The first parameter “typeof(CourseElement)” identifies that this will contain a collection of “CourseElement”; remember that we create the “CourseElement” class in the previous step. The next parameter is “AddItemName = “course”" identifies how the XML element will be reference; for XML element we use lowercase “course”. The last parameter is “CollectionType”; this is set to “ConfigurationElementCollectionType.BasicMap”. If we do not set this value, it will default to “AddRemoveClearMap”. If we use “AddRemoveClearMap”, we would not be able to use the element name “<course”, but instead “<course” would be “<add”. We will “AddRemoveClearMap” when we work with students.
Not that the “CourseElementCollection” inherits from “ConfigurationElementCollection”
Since we declared set the parameters “AddItemName” and “CollectionType” in the C# attribute ConfigurationCollection, we didn’t need to create properties “ConfigurationElementCollectionType” or “ElementName”.
The “<courses>” element contains multiple “<course>” elements. With this in mind, we add the C# property this is the type of CourseElement. Remember we created “CourseElement” class in the previous step.
-
Sanity Check
In the “Program” class lets get data for “Courses”.
Now run the application. You should now see Course information displayed.
Before you move onto the next step, make sure this is working without any errors.
-
Individual Student
Since the collection of students depend on an individual student, we will discuss the makeup of an individual student first.
Here we can see that an individual student, denoted by “<add>” element, has an attribute of “studentId”. So in C# we create a new “StudentElement” class that inherits from “ConfigurationElement”. We have done this multiple time now, so I will not go into details.
-
Collection of Students
Here we will create the code that allows us to work with collection of students. I won’t go over all this code, but I will try to highlight the main sections.
Remember when we worked with collection of courses we used the “CollectionType” of “BasicMap” which allowed us to use the element “<course>”. For collection of students we are going to use the default “CollectionType” of “AddRemoveClearMap”. By using “AddRemoveClearMap” each child element will be an “<add>” element”.
Unlike the “CourseElementCollection”, here we have no C# attribute decorating “StudentElementCollection”; we will use the default values. One of the default values is the CollectionType” of “AddRemoveClearMap. Not that the “StudentElementCollection” inherits from “ConfigurationElementCollection”
Since “<add>” element (student element) is child of the “students” element, we need to add the “StudentElement” class to the “StudentElementCollection”
-
Add Student Collection to CourseElement
Since the “<course>” element contains “<students>” element, we need to include the “StudentElementCollection” class in the “CourseElement” class.
-
Sanity Check
In the “Program” class lets get students for a class.
Now run the application. You should now see Course information displayed.
Oh my that was a lot. But I hope it help you create your own custom C# configurations.
References
