Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

Don’t Use ConfigurationManager!

4.54/5 (9 votes)
15 May 2011CPOL4 min read 75.2K  
If you’re one of those devs that slaps a ConfigurationManager.AppSettings in the middle of a class, then stop, please just stop.

.NET generally has a nice API but some things are problematic when classes are static, like FormsAuthentication or ConfigurationManager, allowing developers to use them anywhere in the code.

If you’re one of those devs that slaps a ConfigurationManager.AppSettings in the middle of a class, then stop, please just stop. I know that it works, but the side effect is that you’re creating a hidden dependency that devs who come along afterwards to maintain the code know nothing about and then get bitten in the ass when they try to change something (yes, I know you should look through the code for things like this, but I was in a hurry, OK?).

To be clear, I believe that settings should be injected into classes that need them rather than having to provide a whole object to handle it (think of a connection string) but if you're refactoring old code and already have the dependency, then it's good to be able to start off by being able to see the dependency rather than have it hidden.

I know what you’re going to say “but it's a static class so I don’t have any other way to use it”, but that’s where you’re wrong, and with a little work, you can have dependency injected, unit tested code loveliness, and in fact, I’ve done the work for you: all you have to do is reuse it!

So what’ve I done? Well, quite simply, just written a wrapper around the ConfigurationManager’s static methods that allow you to use it via an interface and inject it into any class that may need it; let's look at some code to see it a little clearer.

Here, we have an absurdly simple example that demonstrates that just looking at the public interface of this class, you’d have absolutely no idea that it uses ConfigurationManager internally:

C#
1: public class SomeClass
2: {
3:     public void SomeMethod()
4:     {
5:         int value = int.Parse(
                ConfigurationManager.AppSettings["TheValue"]);
6:     }
7: }

At least with the code above, you may go investigating “what lies beneath” and find the hidden dependency, but what if you came across this:

Image 1

My guess is like me, you’d anticipate that the class had been sorted for dependency injection and only needed the two dependencies that its constructor was advertising, and it wasn’t until you got bitten by a problem that you’d look at the code and find:

C#
1: public class SomeClass
2: {
3:     private readonly IDependency1 _firstDependency;
4:     private readonly IDependency2 _secondDependency;
5:  
6:     public public SomeClass(IDependency1 firstDependency, 
              IDependency2 secondDependency)
7:     {
8:         _firstDependency = firstDependency;
9:         _secondDependency = secondDependency;
10:     }
11:  
12:     public void SomeMethod()
13:     {
14:         string theSetting = ConfigurationManager.AppSettings["TheValue"];
15:  
16:         theSetting = theSetting + "ArbitaryValue";
17:  
18:         _secondDependency.TheSetting = theSetting;
19:  
20:     }
21: }

So the solution to both of these problems is to inject the ConfigurationManager into the class and to enable us to do that step forward.

The code is written in .NET 4.0 but should work with .NET 2.0 and above if recompiled to target whatever version of the framework you are working with. For brevities sake, I’m just going to show the second code snippet using IConfigurationManager, which makes the code look like this:

C#
1: public class SomeClass
2:    {
3:        private readonly IConfigurationManager _configurationManager;
4:        ..... 
5:  
6:        public SomeClass(IConfigurationManager configurationManager, 
                           IDependency1 firstDependency, 
7:                         IDependency2 secondDependency)
8:        {....}
9:  
10:        public void SomeMethod()
11:        {
12:            string theSetting = _configurationManager.AppSettings["TheValue"];
13:  
14:            theSetting = theSetting + "ArbitaryValue";
15:  
16:            _secondDependency.TheSetting = theSetting;
17:  
18:        }
19:    }

Now anybody looking at the public interface for this class can see that it has a dependency on IConfigurationManager which in turn should indicate that the code is going to be reading from an App or Web.config. The only difference to the actual code using the configuration setting is the use of the instance variable rather than the static class.

The actual IConfigurationManager project contains the implementations of both ConfigurationManager and WebConfigurationManager (plus tests) to show that you can use IConfigurationManager to replace either of these classes. Currently, only the more common methods and properties have been implemented as following the principle of YAGNI I’ve not bothered adding methods such as OpenExeConfiguration that I don’t need at the moment.

The one extra thing that I have added is the ability to be able to return a strongly typed custom configuration section rather than retrieving a section as an object and then casting it, so instead of:

C#
1: var sect = ConfigurationManager.GetSection("sampleSection")as SampleSectionProvider;

You can do:

C#
1: var sect = _configurationManager.GetSection<SampleSectionProvider>("sampleSection");

I know there’s not a lot of difference but I prefer the generic version since an error will be thrown if it can’t get the appropriate section handler that’s been specified.

One word of warning: the Core project has a dependency on System.Web; this isn’t a problem for me as I’m mostly using this with web projects but if you wanted to use this with a desktop app, you will need to either remove the class from the project or except the assembly dependency.

If you are using ConfigurationManager, then I strongly recommend trying out IConfigurationManager, if not for you, then for the person who has to maintain the code in a few months' time. ;)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)