Introduction
There are a lot of articles that talk about the App.config file for .NET applications, be them Console applications, WinForms applications or Services, not only in CodeProject but all over the internet.
They might all look a like; but the bottom line is that none of them are the same. That's why I'm sure this article won't be the same as all of the other ones you have found and read. Who knows it might help you in some way, or even better you might get some ideas and improve it.
That was my case, I was looking for a custom, general way that I could use to read my App.config, but none of the articles I read convinced me nor solved the need I had at the time but they sure gave me good ideas of what I wanted in my own implementation.
Other people's ideas
There are two main ideas I took from other people in this open source site (of course I'm talking about CodeProject).
Paul Haley wrote in his "Enhanced AppSettings Configuration Handler" article that there are times when you need to try out your application in different environments with different configurations, and editing or commenting code for this matter can be rather annoying. Besides, the App.config is a file where all the configuration should be. (He explains more disadvantages.)
Anyway, his approach is a little more hostname oriented, and if you want to change this, you must inherit from his class and do some other stuff I didn't bother to read.
Diego Mijelshon has an article on "How to make AppSettings work with multiple values for a key". Now, you must agree with me that this is also a good idea. He states clearly that .NET has this serious flaw and he kind of explains the reason. He also shows how to get multiple values for a key, but I think he complicated it a little bit using reflection (not that reflection is hard) for reasons I am not aware of.
I must point out that there is nothing wrong with both articles, they work fine, but my needs were different, so I thought these would be too complicated and I was correct.
Background
It is recommended, of course, to know about appSettings
, the System.Configuration.ConfigurationSettings
class, the App.config file, and XML in which this file is coded. These subjects are rather easy and I guess most [.NET] programmers must know or at least must have heard about them, right?
OK, with this stated... let's get it on!
Main idea
As you might have read, you can get simple values inside the App.config using ConfigurationSettings.AppSettings[...]
or you can create and read custom sections using the ConfigurationSettings.GetConfig(string sectionName)
method, but if you want to read your config file by yourself, you have to create a class that implements the IConfigurationSectionHandler
interface and this is very easy to do, for example:
public class AppSettingHandler : IConfigurationSectionHandler
Doing this forces you to implement a method inside your class, the Create(...)
method, which basically gives you the whole App.config file already in an XmlNode
called section
. Inside the method, you can read the values in any way you want to.
public virtual object Create(object parent, object configContext, XmlNode section)
Using and getting the code right
Now, for your main code to automatically call the Create(...)
method you just implemented, you have to do the following:
First, you must have a valid and correct App.config XML file associated to your application. Inside it you must have something like this, so that you can use the code I'm providing:
="1.0" ="utf-8"
<configuration>
<configSections>
<remove name="appSettings"/>
<section name="appSettings"
type="BellAppSetting.AppSettingHandler, BellAppSetting" />
</configSections>
<appSettings>
-->
</appSettings>
</configuration>
Before I continue, I would like to point out that it is not necessary to remove the appSettings
section, this is just if you want to put your configuration inside the <appSettings>
tag. You can have something like this instead:
="1.0" ="utf-8"
<configuration>
<configSections>
<section name="TheNameIwant"
type="BellAppSetting.AppSettingHandler, BellAppSetting" />
</configSections>
<TheNameIwant>
-->
</TheNameIwant>
</configuration>
Second, you have to call the following line from your main code:
ArrayList nvc;
nvc = (ArrayList)ConfigurationSettings.GetConfig("appSettings");
if you have used <remove name="appSettings"/>
in the App.config file or:
ArrayList nvc;
nvc = (ArrayList)ConfigurationSettings.GetConfig("TheNameIwant");
if you have used <section name="TheNameIwant"
in the App.config file.
The example you get
As you can see from the line called from the code, you receive in return an ArrayList
. Its structure will be shown in the following example. If you want further details, don't hesitate to download the source code.
Say your App.config looks something like this:
="1.0" ="utf-8"
<configuration>
<configSections>
<remove name="appSettings"/>
<section name="appSettings"
type="BellAppSetting.AppSettingHandler, BellAppSetting" />
</configSections>
<appSettings>
<Configs use="true">
<add key="ClientConfig" use="true" />
<add key="ServerConfig" use="true"/>
<add key="OtherValue3" use="false"/>
</Configs>
<Configs use="true">
<add key="ClientConfig" use="true" />
<add key="ServerConfig" use="true"/>
<add key="OtherValue3" use="true"/>
<add key="OtherValue4" use="true"/>
</Configs>
<ClientConfig use="true">
<add key="Address2Connect" value="192.168.1.107"/>
<add key="Port2Connect" value="2000"/>
<add key="Log2File" value="Logging.txt"/>
</ClientConfig>
<ClientConfig use="true">
<add key="Address2Connect" value="192.168.1.105"/>
<add key="Port2Connect" value="2000"/>
</ClientConfig>
<ServerConfig use="true">
<add key="PortListenerName" value="2002"/>
<add key="Port2Listen" value="2002"/>
<add key="PortLisFile2Log" value="Logging.txt"/>
</ServerConfig>
<ServerConfig use="false">
<add key="PortListenerName" value="2004"/>
<add key="Port2Listen" value="2004"/>
<add key="PortLisFile2Log" value="Logging.txt"/>
<add key="PortLisLogAll2File" value="false"/>
<add key="GossipSockets" value ="false"/>
<add key="SocketLogAll2IndependantFile" value="false"/>
</ServerConfig>
<OtherValue4 use="true">
<add key="CheckConnections" value="false"/>
<add key="NotifyUserWhenDone" value="true"/>
<add key="OtherConfigValue" value="1"/>
<add key="OtherConfigValue" value="2"/>
</OtherValue4>
</appSettings>
</configuration>
If you process this App.config with the sample project, you'll get something like this:
Some last notes
- The
<Configs>
node serves as the section collection.
- You can put as many
<Configs>
nodes as you want.
- You can put as many element nodes as you want.
- You can see all nodes have a
use
attribute that can take true
or false
, telling the code if it will be skipped or not.
- A
Hashtable
is used for each element node, so if you repeat them they will be ignored.
- A
DictionaryEntry
is used to allow multiple values for the same key.
Points of Interest
Doing your own implementation of a AppSettings
reader is not as hard as you might think. Of course this depends on how much you want to do, but reading the XmlNode
was pretty easy and straightforward. You receive an ArrayList
with Hashtable
s plus ArrayList
s plus DictionaryEntries
. I know it might sound complicated but searching within is easy and can be done with foreach
s, just as it's shown in the sample project.
If you bother to look at the code, it looks pretty easy, don't you think? This worked for me, and it might work for you too, so take a look.
In resume, this helps you use multiple configurations for your projects by just turning them ON or OFF by changing the use
attribute values and you can also insert multiple values for the same key.
Enjoy! Don't forget, any comments, criticisms, questions or anything are always welcomed!