Simple configuration class

Adding configuration without having to restart app pool

Very often you need to store some settings in your configuration. Web.config files are designed for that but there are two things I found very annoying:

  • You have to declare sections and follow certain rules if you want to add some complex setting
  • Every change of web.config causes application to restart
Note

For application restart behavior when web.config is updated check references for full MSDN article

The first one is not that bad and somehow I can deal with it, but second one is really annoying. In case you need to update settings on your live website, you will cause all existing sessions to drop because whole app will restart as soon as you save your changes in web.config.

This is the main reasons why I use custom config class. It is pretty simple, very easy to access value by XPath.

The whole logic consists of loading and caching XmlDocument class instance and using it for accessing configuration values. Cache policy is set to file dependency, so you do not have to worry about updating values in cache, it is automatically done.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Web;
using System.IO;
namespace Umbraco.Cms.Custom.Configuration
{
public static class Config
{
private const string CACHE_KEY = "1fffcba9-f032-4396-ae0b-59093387fe3b";
public static string ConfigPath
{
get
{
return Path.Combine(HttpContext.Current.Server.MapPath("/Config"), "Website.config");
}
}
public static XmlDocument ConfigDoc
{
get
{
HttpContext webContext = HttpContext.Current;
XmlDocument result = null;
if (webContext.Cache[CACHE_KEY] == null || !(webContext.Cache[CACHE_KEY] is XmlDocument))
{
if (File.Exists(ConfigPath))
{
result = new XmlDocument();
result.Load(ConfigPath);
webContext.Cache.Insert(CACHE_KEY, result, new System.Web.Caching.CacheDependency(ConfigPath));
}
}
else
{
result = webContext.Cache[CACHE_KEY] as XmlDocument;
}
return result;
          }
        }
        public static string GetValueAsString(string XPath, string DefaultValue = "")
        {
            if (!XPath.StartsWith("/"))
            {
                XPath = string.Format("/{0}", XPath);
            }
            if (ConfigDoc != null)
            {
                XmlNode node = ConfigDoc.SelectSingleNode(XPath);
                if (node != null)
                {
                    return node.InnerText;
                }
            }
            return DefaultValue;
        }
        public static int GetValueAsInt(string XPath, int DefaultValue = 0)
        {
            int result = DefaultValue;
            int.TryParse(GetValueAsString(XPath), out result);
            return result;
        }

        public static bool GetValueAsBool(string XPath, bool DefaultValue = false)
        {
            bool result = DefaultValue;
            bool.TryParse(GetValueAsString(XPath), out result);
            return result;
        }
        public static List<string> GetValueAsStringList(string XPath)
        {
            List<string> result = new List<string>();
            XmlNodeList list = ConfigDoc.SelectNodes(XPath);
            if (list != null && list.Count > 0)
            {
                foreach (XmlNode node in list)
                {
                    result.Add(node.InnerText);
                }
            }
            return result;
        }
    }
}
    

To make it more easy to use I added some helper methods to convert your config values in desired type as they are initialy read as a string value. It data does not match the type you try to convert it with a helper method, you will get default value returned for that type:

  • bool GetValueAsBool - false
  • int GetValueAsInt - 0
  • List<string> GetValueAsStringList - new List<string>()

The only rule you need to follow here is to have a file in /Config folder called Website.config with the following structure.

<?xml version="1.0"?>
<config>

</config>
    

This issue can be overcome by writing a short method to check for the file and if it does not exist, to create it. I was just lazy to write it as it was easier to make and empty file with config root nodes :)

What ever you want, in what ever structure, you just add in config node.

As much as I (and I hope you) find it useful, this might not be the best way to do this because XmlDocument class. It is very easy to deserialize valid XML file with XmlDocument class, but this class provides more than just reading xml file, which in this case is the only thing you need (unless you want to be able to update config from code).

Much faster way would be to use XmlReader, but since config (at least most of them I had in apps) are not bigger than few KB this should not take too much of your memory.

References

Disclaimer

Purpose of the code contained in snippets or available for download in this article is solely for learning and demo purposes. Author will not be held responsible for any failure or damages caused due to any other usage.


About the author

DEJAN STOJANOVIC

Dejan is a passionate Software Architect/Developer. He is highly experienced in .NET programming platform including ASP.NET MVC and WebApi. He likes working on new technologies and exciting challenging projects

CONNECT WITH DEJAN  Loginlinkedin Logintwitter Logingoogleplus Logingoogleplus

JavaScript

read more

SQL/T-SQL

read more

Umbraco CMS

read more

PowerShell

read more

Comments for this article