Wrapping .NET Configuration

My rule of thumb for storing configuration settings is:

  • if it does not need to change hard code it
  • if it needs to change but the user of the application can’t change it, store it in the configuration file
  • if the user can change it, store it in a database

This post discusses configuration data stored in the configuration file. For the examples that follow the configuration data might look like:

<appSettings>
    <add key="ForumURLRoot" value="http://someurl" />
    <add key="EmailSendingRetries" value="3" />
</appSettings>

To make my applications robust and testable I like to write a service that wraps appSettings. What I mean by robust is that it provides useful error data in the event that the application depends upon configuration data that is missing. My configuration service throws the following exception if an appSetting is missing:

image

A nice clear error message helps me to rapidly diagnose the problem.

This service is something that I have written many times. To be honest, there is often some copy and paste involved. Here is what the most recent incarnation looks like:

    public interface IConfigService
    {
        string ForumURLRoot();
        int EmailSendingRetries();
    }

    public class ConfigService : IConfigService
    {
        // an example configuration element
        public string ForumURLRoot()
        {
            return ReadSetting("ForumURLRoot");
        }
				
        // an example with a cast
        public int EmailSendingRetries()
        {
            return (int)ReadSetting("EmailSendingRetries");
        }

        private string ReadSetting(string key)
        {
            CheckForKey(key);
            return ConfigurationManager.AppSettings[key];
        }

        private void CheckForKey(string appSettingKey)
        {
            if (ConfigurationManager.AppSettings[appSettingKey] == null 
                || ConfigurationManager.AppSettings[appSettingKey].Equals(string.Empty))
            {
                throw new ConfigurationException("Missing appsetting: " + appSettingKey);
            }
        }
    }

Providing a method for each configuration setting gives me:

  • the ability to cast if the setting needs to be something other than string
  • the ability to easily mock configuration settings for testing

Stubbing a setting, such as ForumURLRoot, is easily accomplished with Moq:

[Test]
public void ConfigMock()
{
   var configMock = new Mock<IConfigService>();
   configMock
       .Expect(config => config.ForumURLRoot())
       .Returns("http://google.com.au");
   Assert.AreEqual("http://google.com.au", configMock.Object.ForumURLRoot());
}

I write this post to expose my ignorance. If I am doing to wrong, let me know.


Comments

Comments are closed