Making Application Configuration Easier Using the Castle DictionaryAdapter

If you've done any development in ASP.NET, you're probably aware of the presence of the <appSettings /> element in web.config that enables you to store centralized configuration settings. You can use that element to store settings such as e-mail addresses and sender names for outgoing e-mail, settings that determine whether or not to send e-mail in certain conditions, default page sizes and a lot more. While this feature greatly decreases the troubles typically associated with configuration settings in multiple deployment scenarios (development versus a production environment for example), you can use an external component called the Castle DictionaryAdapter to make using the appSettings element even easier.

Introduction

Before I show you how to use the DictionaryAdapter component, let's briefly recap how you can use the appSettings element. First, take a look at a quick example of the element that you could have in your web.config file:

<appSettings>
  <add key="MailFromName" value="Your Public Site Name" />
  <add key="MailFromAddress" value="you@yourprovider.com" />
  <add key="SendMailOnError" value="true" />
</appSettings>	    

You can then use these settings in a few different ways. For example, you can access them using expression syntax, and programmatically. The following example access the MailFromName setting and assigns it to a label using expression syntax:

<asp:Label ID="Mail" runat="server" Text="<%$ AppSettings:MailFromName %>" />

When added to a page, this label shows the text "Your Public Site Name".

To access the values stored in web.config and assign it to the same label through code, you use the WebConfigurationManager class like this:

C#
Mail.Text = WebConfigurationManager.AppSettings.Get("FromAddress");

VB Mail.Text = WebConfigurationManager.AppSettings.Get("FromAddress")

The problem with this latter solution is that it gets messy quite quickly. First, you need to write this code every time you need it. Secondly, and more importantly, it doesn't deal with error handling very well (when a key is missing for example), and doesn't provide an easy way to supply a default value. That's why I typically add static and read only properties to a class in my project that serve as wrappers around the appSettings element. The following code snippet shows a quick example:

C#
public static class WebConfiguration
{ 
  /// <summary>
  /// "Old way" property that returns MailFromName.
  /// </summary>
  public static string MailFromName
  {
    get
    {
      string temp = WebConfigurationManager.AppSettings.Get("MailFromName");
      if (!string.IsNullOrEmpty(temp))
      {
        return temp;
      }
      throw new InvalidOperationException(
                    "Can't access key MailFromName in web.config.");
      // Alternatively, return a default value
      // return "Your Public Site Name";
    }
  }
}

VB
Public NotInheritable Class WebConfiguration
  ''' <summary>
  ''' "Old way" property that returns MailFromName.
  ''' </summary>
  ''' <value></value>
  Public Shared ReadOnly Property MailFromName As String
    Get
      Dim temp As String = WebConfigurationManager.AppSettings.Get("MailFromName")
      If Not String.IsNullOrEmpty(temp) Then
        Return temp
      End If
      Throw New InvalidOperationException(
               "Can't access key MailFromName in web.config")
      ' Alternatively, return a default value
      ' Return "Your Public Site Name"
    End Get
  End Property	    
End Class

With this code, you can now assign the MailFromName property to a Label like this:

C#
Mail.Text = WebConfiguration.MailFromName;

VB
Mail.Text = WebConfiguration.MailFromName	    

When the key does not exist, you get a descriptive error message, enabling you to fix the problem as soon as possible (or you get a default value if you modify the property to return one when they key is not found).

While this solution is a lot better than accessing WebConfigurationManager.AppSettings directly, it still suffers from a few problems:

  • The property code contains string literals that map to the keys in web.config. When the two don't match, you may end up with bugs that are hard to track.
  • For each configuration key you add to web.config, you need to add the property code as shown here, over and over again. While you could abstract away some of the logic to a separate class or method, you still end up with a lot of repetitive and difficult to maintain code.

Introducing Castle DictionaryAdapter

Fortunately, there is an easy way to fix this, using Castle's DictionaryAdapter. The DictionaryAdapter is part of the open source Castle project, an "open source project for .net that aspires to simplify the development of enterprise and web applications". The DictionaryAdapter lives up to that promise by making it easy to wrap your configuration keys through easy accessible properties, based on the definition of a custom interface.

To get started with the DictionaryAdapter, follow these steps:

  1. Download the DictionaryAdapter Component from the Castle web site.
  2. Extract the Castle.Components.DictionaryAdapter.dll assembly to a folder on your hard drive and from a web project (or any other .NET project) add a reference to it.
  3. Create an interface that defines the names and types of the properties you want to expose. In my case, I added an interface that looks like this:

    C#
    public interface ISettings
    {
      string MailFromName { get; }
      string MailFromAddress { get; }
      bool SendMailOnError{ get; }
    }
    
    VB
    Public Interface ISettings
      ReadOnly Property MailFromName() As String
      ReadOnly Property MailFromAddress() As String
      ReadOnly Property SendMailOnError() As Boolean
    End Interface
    	        
  4. Create a class that serves as the configuration wrapper (called WebConfiguration for example) and add the following code:

    C#
    public static class WebConfiguration
    {
      static ISettings _settings;
      /// <summary>
      /// Returns the current configuration settings for this web site.
      /// </summary>
      public static ISettings Current
      {
        get
        {
          if (_settings == null)
          {
            var factory = new DictionaryAdapterFactory();
                  _settings = factory.GetAdapter<ISettings>(
            WebConfigurationManager.AppSettings);
          }
          return _settings;
        }
      }
    }          
    
    VB
    Public NotInheritable Class WebConfiguration
      Private Shared _settings As ISettings
      ''' <summary>
      ''' Returns the current configuration settings for this web site.
      ''' </summary>
      Public Shared ReadOnly Property Current() As ISettings
        Get
          If _settings Is Nothing Then
            Dim factory = New DictionaryAdapterFactory()
            _settings = factory.GetAdapter(Of ISettings) _
                       (WebConfigurationManager.AppSettings)
          End If
          Return _settings
        End Get
      End Property
    End Class
    The GetAdapter<T> method of the DictionaryAdapterFactory does all the magic and creates an object with getters and setters around the dictionary (the NamedValueCollection AppSettings) in this case. The cool thing about the adapter is that you're not limited to the AppSettings element. Anything that inherits IDictionary (quite a lot of classes do in .NET) can be used to provide a type-safe wrapper as shown here. Another common usage for this is to wrap the ASP.NET Session store to create type-safe session variables.
    The code uses static variables to create a singleton Current property that serves as the main configuration entry point for the entire application. Assigning one of the values from the appSettings element to a Label can now be done like this:

    C#
    Mail.Text = WebConfiguration.Current.MailFromName;
    
    VB
    Mail.Text = WebConfiguration.Current.MailFromName
    Clean, simply, and easy to maintain. Whenever you need to add an additional configuration setting, all you have to do is add the key to the web.config file, and add an additional member to the ISettings interface. After that, your property becomes available automatically on the Current property of the WebConfiguration class.

Downloads


Where to Next?

Wonder where to go next? You can post a comment on this article.

Doc ID 550
Full URL https://imar.spaanjaars.com/550/making-application-configuration-easier-using-the-castle-dictionaryadapter
Short cut https://imar.spaanjaars.com/550/
Written by Imar Spaanjaars
Date Posted 07/30/2010 14:17

Comments

Talk Back! Comment on Imar.Spaanjaars.Com

I am interested in what you have to say about this article. Feel free to post any comments, remarks or questions you may have about this article. The Talk Back feature is not meant for technical questions that are not directly related to this article. So, a post like "Hey, can you tell me how I can upload files to a MySQL database in PHP?" is likely to be removed. Also spam and unrealistic job offers will be deleted immediately.

When you post a comment, you have to provide your name and the comment. Your e-mail address is optional and you only need to provide it if you want me to contact you. It will not be displayed along with your comment. I got sick and tired of the comment spam I was receiving, so I have protected this page with a simple calculation exercise. This means that if you want to leave a comment, you'll need to complete the calculation before you hit the Post Comment button.

If you want to object to a comment made by another visitor, be sure to contact me and I'll look into it ASAP. Don't forget to mention the page link, or the Doc ID of the document.

(Plain text only; no HTML or code that looks like HTML or XML. In other words, don't use < and >. Also no links allowed.