I recently needed a configuration mechanism which would detect changes without requiring an application domain restart. I also wanted to move away from XML. This is what I came up with (and hopefully I'll get some helpful feedback).
First, we declare a ConfigurationData object which holds our actual configuration values:
public interface IConfigurationData
{
bool LogAll{ get; }
string CdnUrl{ get; }
}
public class ConfigurationData : IConfigurationData
{
private bool _logAll;
private int _cdnUrl;
public bool LogAll
{
get { return _logAll; }
set{ _logAll = value; }
}
public string CdnUrl
{
get { return _cdnUrl; }
set { _cdnUrl = value; }
}
}
There isn't much to explain here, so let's move on to the class that does the heavy lifting:
public static class Configuration
{
private static readonly string _applicationPath = HttpRuntime.AppDomainAppPath;
private static ConfigurationData _instance = LoadInitialConfiguration();
public static IConfigurationData GetInstance
{
get { return _instance; }
}
private static ConfigurationData LoadInitialConfiguration()
{
var watcher = new FileSystemWatcher(_applicationPath, "settings.config");
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.Changed += (s, e) => _instance = LoadConfiguration();
watcher.EnableRaisingEvents = true;
return LoadConfiguration();
}
private static ConfigurationData LoadConfiguration()
{
return Converter.DeserializeFromFile<ConfigurationData>(_applicationPath + "settings.config", "_");
}
}
The class essentially loads the ~settings.config file, and sets up a watch to reload it whenever it changes. Here I'm using JSON (and my own JSON library) to read the file, but you could use anything, such as yaml or xml. The file might look something like:
{
"logAll": true,
"_cdnUrl": "http://cdn.mysite.com/"
}
If you are using a DI framework, such as ninject, you can hook it via:
Bind<IConfigurationData>().ToMethod(c => Configuration.GetInstance);
otherwise, you can call it directly from code with:
if (Configuration.GetInstance.LogAll) {...}
There are two things you'll need to be careful with. First you'll want to make sure to avoid caching values within a class. For example, if you did something like:
public static class HtmlExtensions
{
private static readonly string _cdnUrl = Configuration.GetInstance.CdnUrl;
}
then a copy of CdnUrl would be stored in _cdnUrl and changes to your file wouldn't be available to this class.
Secondly, the Changed event is known to fire twice. This shouldn't cause any threading issues, but if your LoadConfiguration is particularly intensive, or if you happen to be debugging something, then you'll at least know to expect it.
Posted
Thu, Jan 28 2010 9:43 AM
by
karl