Objective
After completing this exercise, you should be able to implement custom configSection
, with nested elements, in your application’s config file.
In my previous post, How to implement custom configSection in your configuration, I have explained the details about how to implement simple single element based custom configSection
in your configuration, i.e., without any nested elements.
However in many scenarios, we need to implement custom configSection
having nested elements. It is very useful in cases where you need to store some limited number of configuration details or any data, and you do not want to use database for storing those configurations.
Here, I will explain the step by step process to implement custom configSection
with nested elements. Like most of my posts, I have followed a practical approach rather than providing theory. Following this, you will be able to achieve the goal of the post.
Step 1
Create a new Console application named as “CustomNestedConfigSection
”.
Step 2
Create a folder under this project named as “NestedConfig”.
Step 3
Add a new App.config file to the project.
Step 4
Add a new class file “EmployeesConfigSection.cs” in NestedConfig folder as below:
using System.Configuration;
namespace CustomNestedConfigSections.NestedConfig
{
public class EmployeesConfigSection : ConfigurationSection
{
[ConfigurationProperty("employeeCollection", IsDefaultCollection = true,
IsKey = false, IsRequired = true)]
public EmployeeCollection Members
{
get
{
return base["employeeCollection"] as EmployeeCollection;
}
set
{
base["employeeCollection"] = value;
}
}
}
}
Step 5
Add a new class file “EmployeeCollection.cs” in NestedConfig folder as below:
using System;
using System.Configuration;
namespace CustomNestedConfigSections.NestedConfig
{
public class EmployeeCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new Employee();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((Employee) element).Id;
}
protected override string ElementName
{
get
{
return "employee";
}
}
protected override bool IsElementName(string elementName)
{
return !String.IsNullOrEmpty(elementName) && elementName == "employee";
}
public override ConfigurationElementCollectionType CollectionType
{
get
{
return ConfigurationElementCollectionType.BasicMap;
}
}
public Employee this[int index]
{
get
{
return base.BaseGet(index) as Employee;
}
}
public new Employee this[string key]
{
get
{
return base.BaseGet(key) as Employee;
}
}
}
}
Step 6
Add a new class file “Employee.cs” in NestedConfig folder as below:
using System.Configuration;
namespace CustomNestedConfigSections.NestedConfig
{
public class Employee : ConfigurationElement
{
[ConfigurationProperty("id", IsKey = true)]
public string Id { get { return (string) this["id"]; } }
[ConfigurationProperty("personalInfo")]
public PersonalInfo PersonalInfo
{
get { return (PersonalInfo)this["personalInfo"]; }
}
[ConfigurationProperty("homeAddress")]
public Address HomeAddress { get { return (Address)this["homeAddress"]; } }
[ConfigurationProperty("officeAddress")]
public Address OfficeAddress { get { return (Address)this["officeAddress"]; } }
}
}
Step 7
Add a new class file “PersonalInfo.cs” in NestedConfig folder as below:
using System.Configuration;
namespace CustomNestedConfigSections.NestedConfig
{
public class PersonalInfo : ConfigurationElement
{
[ConfigurationProperty("ssn", IsKey = true)]
public string SSN { get { return (string)this["ssn"]; } set { this["ssn"] = value; } }
[ConfigurationProperty("height")]
public int Height { get { return (int)this["height"]; } set { this["height"] = value; } }
[ConfigurationProperty("weight")]
public int Weight { get { return (int)this["weight"]; } set { this["weight"] = value; } }
}
}
Step 8
Add a new class file “Address.cs” in NestedConfig folder as below:
using System.Configuration;
namespace CustomNestedConfigSections.NestedConfig
{
public class Address : ConfigurationElement
{
[ConfigurationProperty("pin")]
public string PinCode { get { return (string) this["pin"]; } }
[ConfigurationProperty("city")]
public string City { get { return (string)this["city"]; } }
[ConfigurationProperty("state")]
public string State { get { return (string)this["state"]; } }
}
}
Step 9
Modify “App.config” file in your application as below:
="1.0" ="utf-8"
<configuration>
<configSections>
<section name="employeeCollectionSection"
type="CustomNestedConfigSections.NestedConfig.EmployeesConfigSection,
CustomNestedConfigSections"/>
</configSections>
<employeeCollectionSection>
<employeeCollection>
<employee id="1">
<personalInfo ssn="3243423" height="342" weight="78" />
<homeAddress pin="411001" city="Pune" state="Maharashtra"/>
<officeAddress pin="844101" city="Shahdra" state="Delhi"/>
</employee>
<employee id="2">
<personalInfo ssn="7435623" height="342" weight="62" />
<homeAddress pin="411002" city="Pimpri" state="Maharashtra"/>
<officeAddress pin="874785" city="Mangolpuri" state="Haryana"/>
</employee>
</employeeCollection>
</employeeCollectionSection>
</configuration>
Step 10
Modify “Program.cs” file in your application as below:
using System;
using System.Configuration;
using CustomNestedConfigSections.NestedConfig;
namespace CustomNestedConfigSections
{
class Program
{
static void Main(string[] args)
{
var employee1 = GetEmployee("1");
Console.WriteLine("\n\nDetails of employee with id : 1");
Console.WriteLine("Personal Info: SSN - {0} Height - {1}inch Weight - {2}Kg",
employee1.PersonalInfo.SSN, employee1.PersonalInfo.Height,employee1.PersonalInfo.Weight);
Console.WriteLine("Home Address : {0} {1} {2}", employee1.HomeAddress.City,
employee1.HomeAddress.State, employee1.HomeAddress.PinCode);
Console.WriteLine("Office Address : {0} {1} {2}", employee1.OfficeAddress.City,
employee1.OfficeAddress.State, employee1.OfficeAddress.PinCode);
Console.ReadKey();
}
public static Employee GetEmployee(string employeeId)
{
var employeesConfigSection = ConfigurationManager.GetSection
("employeeCollectionSection") as EmployeesConfigSection;
if (employeesConfigSection == null ||
employeesConfigSection.Members == null || employeesConfigSection.Members.Count < 1)
return null;
return employeesConfigSection.Members[employeeId];
}
}
}
Step 11
Run your console application. Do not forget to add reference of “System.Configuration
” in your console application project. I hope you will not get any error while running the application. However if you get one, you would be able to fix it.
Now I will explain the terms or points which have not been covered above.
- For each element/node in your config, you need to create a corresponding class which derives from “
ConfigurationElement
”.
- To define an attribute for any element/node, you need to create a
public
property with “ConfigurationProperty
” attribute. For example, if you want to create an attribute named “city
” for an element, then define a property like:
[ConfigurationProperty("city")]
public string City { get { return (string)this["city"]; } }
- You define the name of element/node/attribute inside “
ConfigurationProperty
” attribute.
- If you want more than one child node under an element or node, then you need to create a new class for that collection which should be derived from “
ConfigurationElementCollection
”. Here, you also define name of the element which represents your collection as I have created “employee
" for employee collection.
- To create root element/node for your
configSection
, you must create a class which derives from “ConfigurationSection
”. To create simplest configSection
, you need a single class derived from “ConfigurationSection
” having properties, with ConfigurationProperty
attribute, corresponding to required attributes.
- If you do not want wrapper element/node for your collection, then replace
ConfigurationProperty
name with blank. For example, if you do not want “employeeCollection
” element/node in your config file, then replace ConfigurationProperty
name with blank from EmployeesConfigSection
as below:
[ConfigurationProperty("", IsDefaultCollection = true, IsKey = false, IsRequired = true)]
public EmployeeCollection Members
{
get
{
return base[""] as EmployeeCollection;
}
set
{
base[""] = value;
}
}
After making the above changes, configSection
in your App.config file should be modified as:
<employeeCollectionSection>
<employee id="1">
<personalInfo ssn="3243423" height="342" weight="78" />
<homeAddress pin="411001" city="Pune" state="Maharashtra"/>
<officeAddress pin="844101" city="Shahdra" state="Delhi"/>
</employee>
- You will have n level of nesting of elements in this way. You will have n classes for n elements you need in your configuration.
- You can define a
static
class for easy manipulation of configuration values. I have defined static
methods in Program
class for the purpose to get employee
with given id.