Sometimes you want to store settings in a config file like web.config or app.config for your modules. In this small tutorial I will show you how to do that. I will not only show you how to define your own sections but also how to put this config in a separate file.
It actually doesn’t matter if you are building a MVC application or a console application. The way you create custom config sections is the same for both with the exception that for a MVC application you define them in the web.config and for console applications your define them in the app.config.
Lets say we have a budgetplanner MVC application and this application has 4 sections where you can create teams, customers, projects and budgets. Every section has its how pagination which can be configured in the web.config. You can configure for example the amount of items per page and how many pages should be visible in the pagination. A config section for this could look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<planner> <section id="teams"> <pagination itemsperpage="10" visiblePages="10" /> </section> <section id="klanten"> <pagination itemsperpage="10" visiblePages="10" /> </section> <section id="projecten"> <pagination itemsperpage="10" visiblePages="10" /> </section> <section id="budgets"> <pagination itemsperpage="10" visiblePages="10" /> </section> </planner> |
Lets start by putting this config section in the web.config file under the node
<configuration> … </configuration>. We also need to define this config section inside the node configsections. So your web.config will now look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<configuration> <configSections> .... <section name="planner" type="BudgetPlanner.Business.PlannerSection" allowLocation="true" allowDefinition="Everywhere"/> </configSections> ... <planner> <section name="teams"> <pagination itemsperpage="10" visiblePages="10" /> </section> </planner> </configuration> |
Important: For now lets have only one section with the name “teams” to keep it simple. Later we will add more then one section like above but this requires extra coding.
Take a closer look at the configsection we just added. The name attribute of the configsection is the name of the node. The node is <planner> so the name is planner. The type attribute points to the class which defines this section.
This is the point were it gets a bit more complicated. We like all configs to be strongly typed that’s why we need a class that defines the structure of our configsection.
So lets create a file PlannerSection.cs with an empty class like this:
1 2 3 4 |
public class PlannerSection : ConfigurationSection { ... } |
This class is going to define our config section. The first node in our config is called section. I know that the name is a bit confusing here but remember this is an arbitrary name. We could also called it ‘page’ or ‘part’ or whatever your like. We need to define this node in our class like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class PlannerSection : ConfigurationSection { [ConfigurationProperty("section")] public Section Section { get { return (Section)this["section"]; } set { this["section"] = value; } } } |
For each node you need a property to get or set the node object and you need a node object that defines the attributes of the node. So the above property gives us access to the node object and returns and object called Section which defines the node attributes. So next we need to create this object.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class Section : ConfigurationElement { [ConfigurationProperty("id", IsKey = true, IsRequired = true)] public string Id { get { return (string)this["id"]; } } [ConfigurationProperty("pagination")] public Pagination Pagination { get { return (Pagination)this["pagination"]; } set { this["pagination"] = value; } } } |
Every section has a name so the section object has a property called name. Every section node also has a child node called pagination so it also needs a property called pagination to get this node object. Now lets also create a pagination object:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public class Pagination : ConfigurationElement { [ConfigurationProperty("itemsperpage", DefaultValue = "10", IsRequired = true)] [IntegerValidator(ExcludeRange = false, MaxValue = 50, MinValue = 1)] public int Itemsperpage { get { return (int)this["itemsperpage"]; } set { this["itemsperpage"] = value; } } [ConfigurationProperty("visiblePages", DefaultValue = "10", IsRequired = true)] [IntegerValidator(ExcludeRange = false, MaxValue = 50, MinValue = 1)] public int VisiblePages { get { return (int)this["visiblePages"]; } set { this["visiblePages"] = value; } } } |
That’s it. Now we have fully defined the new configsection. You can access the config now from a controller like this:
1 2 |
PlannerSection config = (PlannerSection) ConfigurationManager.GetSection("planner"); |
How to support multiple <section> tags
Remember that our original config had multiple <section> tags each with its own name and child nodes. If you add another <section> tag now you will get an error when trying to load the config section ‘planner’. To support multiple <section> tags we need a ConfigurationElementCollection
wrapper. So replace the property Section in the class PlannerSection with a property Sections that looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class PlannerSection : ConfigurationSection { [ConfigurationProperty("", IsDefaultCollection = true, IsKey = false, IsRequired = true)] public SectionCollection Sections { get { return base[""] as SectionCollection; } set { base[""] = value; } } } |
And create a SectionCollection object/class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
public class SectionCollection : ConfigurationElementCollection { protected override ConfigurationElement CreateNewElement() { return new Section(); } protected override object GetElementKey(ConfigurationElement element) { return ((Section)element).Id; } protected override string ElementName { get { return "section"; } } protected override bool IsElementName(string elementName) { return !String.IsNullOrEmpty(elementName) && elementName == "section"; } public override ConfigurationElementCollectionType CollectionType { get { return ConfigurationElementCollectionType.BasicMap; } } public Section this[int index] { get { return base.BaseGet(index) as Section; } } public new Section this[string key] { get { return base.BaseGet(key) as Section; } } } |
Now you can loop through all sections using this code:
1 2 3 4 5 6 7 8 9 |
PlannerSection config = (PlannerSection)ConfigurationManager.GetSection("planner"); foreach (Section section in config.Sections) { Debug.WriteLine(section.Id); Debug.WriteLine(section.Pagination.Itemsperpage); Debug.WriteLine(section.Pagination.VisiblePages); } |
Putting your config in an external file
This is really simple. Just replace the section:
1 2 3 |
<planner> ... </planner> |
with
1 |
<planner configSource="Planner.config" /> |
In your web.config and create a new file Planner.config. This new file should then contain this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<planner> <section id="teams"> <pagination itemsperpage="10" visiblePages="10" /> </section> <section id="klanten"> <pagination itemsperpage="10" visiblePages="10" /> </section> <section id="projecten"> <pagination itemsperpage="10" visiblePages="10" /> </section> <section id="budgets"> <pagination itemsperpage="10" visiblePages="10" /> </section> </planner> |