IanG on Tap

Ian Griffiths in Weblog Form (RSS 2.0)

Blog Navigation

April (2018)

(1 item)

August (2014)

(1 item)

July (2014)

(5 items)

April (2014)

(1 item)

March (2014)

(1 item)

January (2014)

(2 items)

November (2013)

(2 items)

July (2013)

(4 items)

April (2013)

(1 item)

February (2013)

(6 items)

September (2011)

(2 items)

November (2010)

(4 items)

September (2010)

(1 item)

August (2010)

(4 items)

July (2010)

(2 items)

September (2009)

(1 item)

June (2009)

(1 item)

April (2009)

(1 item)

November (2008)

(1 item)

October (2008)

(1 item)

September (2008)

(1 item)

July (2008)

(1 item)

June (2008)

(1 item)

May (2008)

(2 items)

April (2008)

(2 items)

March (2008)

(5 items)

January (2008)

(3 items)

December (2007)

(1 item)

November (2007)

(1 item)

October (2007)

(1 item)

September (2007)

(3 items)

August (2007)

(1 item)

July (2007)

(1 item)

June (2007)

(2 items)

May (2007)

(8 items)

April (2007)

(2 items)

March (2007)

(7 items)

February (2007)

(2 items)

January (2007)

(2 items)

November (2006)

(1 item)

October (2006)

(2 items)

September (2006)

(1 item)

June (2006)

(2 items)

May (2006)

(4 items)

April (2006)

(1 item)

March (2006)

(5 items)

January (2006)

(1 item)

December (2005)

(3 items)

November (2005)

(2 items)

October (2005)

(2 items)

September (2005)

(8 items)

August (2005)

(7 items)

June (2005)

(3 items)

May (2005)

(7 items)

April (2005)

(6 items)

March (2005)

(1 item)

February (2005)

(2 items)

January (2005)

(5 items)

December (2004)

(5 items)

November (2004)

(7 items)

October (2004)

(3 items)

September (2004)

(7 items)

August (2004)

(16 items)

July (2004)

(10 items)

June (2004)

(27 items)

May (2004)

(15 items)

April (2004)

(15 items)

March (2004)

(13 items)

February (2004)

(16 items)

January (2004)

(15 items)

Blog Home

RSS 2.0

Writing

Programming C# 5.0

Programming WPF

Other Sites

Interact Software

Configuration Section Handlers - What Are They Good For?

Monday 28 June, 2004, 11:05 AM

(Huh!)

Philip Haack recently linked to Craig Andera's article showing a generic configuration section handler.

Craig's example is undoubtedly an elegant way of providing a configuration section handler. However, I don't really like configuration section handlers much. My explanation of why has turned out to be quite large. Regular readers of this blog will be unsurprised, I suspect...

.NET Application Configuration Files

In case you've not come across these things, XML Configuration Section handlers can be used to extract information from a .NET application configuration file.

Any application can have a configuration file. In the case of an ASP.NET application, it's the web.config file, and in most other apps, it's called SomeApp.exe.config, where SomeApp.exe is the filename of the main executable. (Incidentally, the main executable doesn't actually have to be a .NET app. If it's an unmanaged app that uses .NET components via a COM Callable Wrapper supplied by the interop layer, the CLR will still look for a config file named for the main EXE.)

Various .NET Framework features can be configured through this file, such as the assembly resolver, or ASP.NET. You can also put your own name-value pairs in the file, e.g.:

<configuration>
    <appSettings>
        <add key='dbconn'
             value='Data Source=dbsrv;Initial Catalog=mydb;Integrated Security=SSPI";'/>
    </appSettings>
</configuration>

This can then be retrieved using code like this:

using System;
using System.Configuration;

class DbUtils
{
    internal static string ConnectionString
    {
        get
        {
            if (connStr == null)
            {
                connStr = ConfigurationSettings.AppSettings["dbconn"];
            }
            return connStr;
        }
    }
    private static string connStr;
}

In this particular case there's no need for a configuration section handler - we can just use the built in ConfigurationSettings class's AppSettings property to retrieve stuff from the <appSettings> element.

So why would you use a configuration file section handler when you can just use <appSettings>?

Configuration Section Handlers

There are two good reasons you might want to avoid the <appSettings> element. One is that if you are configuring some reusable subsystem which might appear in multiple applications, it's hard to guarantee the uniqueness of the key names. Another is that you might have a considerable number of settings to configure, and it can be more convenient and compact to put it in a more specialised XML structure. For example, when you compare it with how ASP.NET settings look in a web.config file, the <appSettings> element looks pretty ungainly.

The configuration section handler system provides a standard way of defining new section types for your configuration files. It essentially lets you do exactly the same thing as all of the various parts of the .NET framework that use the config file. (Craig's article covers the details admirably, so I won't say any more here.)

Problems with Section Handlers

The main thing I dislike about XML configuration section handlers is that you have to put a bunch of cruft into the configuration file to tell .NET about the handler. This has to appear in the <configSections> element at the start of the application's config file. This feels like the wrong place to me - I think it should be down to the code that reads the config section in question to specify that information, rather than forcing every single application to include it in their config files.

The parts of the .NET framework that use the config file get away without forcing the user to add a <configSections> element because the machine-wide machine.config file contains a <configSections> element listing all the default sections. But for custom sections, then unless you have some way of changing the machine.config file (which is typically a bad idea) the custom configuration section handler will have to be listed in the application's config file.

That's pretty clunky. What I want to be able to do is have a config file that looks more or less like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <MyStuff>
    <Foo>1.234</Foo>
    <Bar>A bunch of information</Bar>
  </MyStuff>
</configuration>

(Note the lack of a <configSections> element.) And I want my code to look something like this:

public class MyStuff
{
    public double Foo;
    public string Bar;
}

...

MyStuff myStuff = (MyStuff) GenericConfig.GetConfig(typeof(MyStuff));

In other words, I don't want to have to put extra cruft in my configuration file. And in theory this is easy to achieve - just write your own code to parse the configuration file. (In the code snippet above, that would be the GenericConfig class, which has supplanted the system ConfigurationSettings class.) This is a much simpler mechanism to use - the API is about the same as before - just a different class name - and you avoid the usual boilerplate that configuration section handlers require in the configuration file.

Sadly it doesn't work.

The CLR gets upset if you put elements it doesn't know about in the configuration file. So this would appear to force you to put a <configSections> element in there even if you are prepared to write your own code to parse the whole file.

You might hope to get away with it if you could be absolutely sure that nothing else will try to load the configuration file. However, lots of things do try to load it, and not necessarily when you'd expect. For example, the XmlSerializer class appears to do so - if you have unrecognized elements in your config file, it throws a System.Configuration.ConfigurationException when you first instantiate an XmlSerializer of any kind. This isn't documented. Who knows what other parts of the .NET Framework Class Libraries may implicitly try to load the configuration file and throw an exception if it's not valid? (It's at moments like these that I sometimes pine for Java's checked exception mechanism... Or at least I would if I believed it could solve this problem fully.) And in any case, if the configuration file looks invalid, this is likely to disable other uses of the file, such as assembly version redirects. So this isn't really a viable approach.

Unfortunately, there doesn't seem to be any programmatic way of adding extra configuration section handlers at runtime. This is a little curious, because it doesn't look like custom section handlers ever get loaded automatically - they have to be asked for at runtime before they are loaded. So it's not like you wouldn't have the opportunity to register one programmatically. But there doesn't seem to be any API for doing this. I suppose the reason for this is that the CLR wants to be able to decide whether the configuration file is valid when it first loads it.

One way of working around this is to put a second configuration file in your application. For example, as well as a MyProgram.exe.config file, there's nothing stopping you from also having a MyProgram.exe.moreconfig file. And the following class will let you extract data from it:

using System;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

public class GenericConfig
{
    public static object GetConfig(Type t)
    {
        // The simplest thing to do here would be presume that we can
        // use the name MyApp.exe.config in the AppBase directory.
        // However, it's possible for the creator of the AppDomain to
        // supply a different configuration file. ASP.NET uses a
        // different name, for example (web.config). NUnit also
        // supplies a non-default config file path when testing DLLs.
        //
        // So to be on the safe side, we strip off the extension
        // (typically ".config") from the current configuration file
        // path, and replace it with ".moreconfig"

        AppDomainSetup domainInfo = AppDomain.CurrentDomain.SetupInformation;
        string originalConfigFile = domainInfo.ConfigurationFile;
        string configFileName =
            Path.GetFileNameWithoutExtension(originalConfigFile)
            + ".moreconfig";
        string configFile = Path.Combine(
            Path.GetDirectoryName(originalConfigFile), configFileName);

        XmlDocument configDocument = new XmlDocument();
        configDocument.Load(configFile);

        string configElementName = t.Name;

        XmlNode configNode = configDocument.SelectSingleNode(
            "/configuration/" + configElementName);
        if (configNode == null) return null;

        XmlSerializer configSerializer = new XmlSerializer(t);
        return configSerializer.Deserialize(new XmlNodeReader(configNode));
    }
}

Now we can use the code snippet from earlier:

MyStuff myStuff = (MyStuff) GenericConfig.GetConfig(typeof(MyStuff));

This works just fine without any configuration section handlers, because we're no longer putting things in the file that the CLR thinks it controls. But it's not ideal - having an extra configuration file looks messy. It's also likely to confuse people first time they see it, as this is a pretty non-standard idiom.

Cure Worse Than The Disease?

You might look at that previous example, and think that it would probably be less effort to put the <configSections> boilerplate in the configuration file. After all, it's shorter than that class above. Moreover, even if you add together Craig's section handler class and the necessary boilerplate, it still comes out slightly shorter than my code...

In some cases, it will be simpler to live with the boilerplate. It really depends on where you want to put the burden of effort. If the relevant configuration settings will only ever be used by a single application, you may as well go for the configuration section handler. This alternative approach only pays dividends if the same configuration settings are used in multiple applications.

So if you're writing a component that will be used in multiple applications, and which requires configuration settings, then my GenericConfig class only needs to be put in that component the once. This will then save developers who use that component from the hassle of putting in the <configSections> boilerplate for every application.

Of course the weirdness of having two configuration files may well be enough to put you off even in this case.

As it happens, I've never actually shipped anything using the code above. It's simply that I've found configuration section handlers slightly irritating for some time now, and this is as far as I've got with trying to come up with something better. I don't think I'm there yet.

But then should you be using the config file at all?

When Configuration Section Handlers Are the Wrong Thing

There is a tendency for the application configuration file to be overused. A lot of people try to put user settings in there. This is a really bad idea for two reasons.

First, to be able to save information in the application configuration file, users will require write access to it. Normal user accounts won't have that - application installation directories are locked down, and with good reason. So by using this technique for user settings, you would be forcing users to run as members of either the Power Users or the Administrators group. This is bad.

Second, it doesn't work in multi-user scenarios. And if you think these are edge cases that only concern relatively rare terminal services environments, think again. Desktop systems may well have multiple different people logging into them over time. In fact in Windows XP, they may even be logged in simultaneously. (Unless you're a member of a domain, in which case fast user switching is disabled. Grr!)

It's also not that easy - there's no API for modifying the config file. This is not an error of omission though - it's to discourage you from doing it, because it's a bad idea.

The config file is really only for settings chosen at deployment time which are unlikely to change thereafter. For example, they're probably a reasonable choice for database connection information, so that you can configure your development, test, staging, and production servers to point at different databases.

But for anything else, I'd recommend considering the Configuration Management Application Block for .NET.

Copyright © 2002-2024, Interact Software Ltd. Content by Ian Griffiths. Please direct all Web site inquiries to webmaster@interact-sw.co.uk