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 read existing comments below or you can post a comment yourself on this article .


Consider making a donation
Please consider making a donation using PayPal. Your donation helps me to pay the bills so I can keep running Imar.Spaanjaars.Com, providing fresh content as often as possible.



Feedback by Other Visitors of Imar.Spaanjaars.Com

On Saturday, July 31, 2010 4:58:24 PM Nick said:
Thanks for writing this blog post. I think wrapping the session with this, as you suggest, could be quite handy.
On Sunday, August 01, 2010 8:34:54 AM Imar Spaanjaars said:
Hi Nick,

Yes, that indeed makes it easier to deal with session variables, especially when you have nullable types: http://www.castleproject.org/components/dictionaryadapter/nullables.html

Cheers,

Imar
On Sunday, August 01, 2010 10:12:07 AM Victor said:
Thank for the article
But I still can not implement this with Session
I read the link you posted, but how they define Session object they passed in GetAdapter method.
Is it HttpContext.Current.Session ?
On Sunday, August 01, 2010 11:54:37 AM Imar Spaanjaars said:
>> Is it HttpContext.Current.Session ?

Yes, most likely. Since you're probably not using the code in a Page, you need to access the Session like that.

Cheers,

Imar
On Wednesday, February 09, 2011 4:22:32 AM Paul Huff said:
Okay. I cannot use the Session object with this.  What gives?  I get Cannot convert from 'System.Web.SessionState.HttpSessionState' to 'System.Collections.IDictionary'.

So all the hype about using this in a Session, only to get this error.  Very frustrating!
On Wednesday, February 09, 2011 7:56:52 AM Imar Spaanjaars said:
Hi Paul,

Hype?

You may want to take a look at these articles:

http://blog.jason.smale.org/2010/08/dictionary-adapter-for-httpsessionstate_15.html
http://groups.google.com/group/castle-project-devel/msg/eb2b11fb703d5787?pli=1

They show you how to create a wrapper around Session state.

Cheers,

Imar
On Friday, February 18, 2011 9:08:41 AM Hossam El-Deen said:
Thanks for writing this post, Really it is a very good way to wrap AppSettings.

Keep it up :)
On Thursday, October 03, 2013 8:30:04 PM Laura Thomas said:
Are they no longer supporting this project?  The link doesn't work and when I search for DictionaryAdapter on the site it is also a dead link.  Bummer!
On Friday, October 04, 2013 7:51:52 PM Imar Spaanjaars said:
Hi Laura,

Yeah, it looks like it. It's still listed on the Projects page, but with the same dead link.

Cheers,

Imar

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 QuickDocId of the document.

For more information about the Talk Back feature, check out this news item.