Introduction
It is important to be able to configure an application behavior at runtime. But it should be noted that there is a great difference between configuring an application that is deployed to a single machine and configuring one that is deployed to a distributed environment. The latter demands that all the participated machines must have the same configuration parameters at the same time. So, from the above perspective, we can separate two major kinds of configuration management. The first one is configuring an application via a configuration file. And, the second one is database server side configuration storage.
File configuration storage
One of the most propagated solutions is the usage of “*.config” files. The Microsoft .NET Framework has a special assembly “System.Configuration” that allows working with this. Also, there is an useful addition in the “Enterprise Library Configuration Application Block” which presents the FileConfigurationSource
class for working with “*.config” files (one of the most interesting features is the ability to watch for file modifications and reload them on the spot).
I will introduce a solution that is based on custom System.Configuration.ConfigurationSection
and Microsoft.Practices.EnterpriseLibrary. Common.Configuration.FileConfigurationSource
. The main bonuses of using this kind of configuration management are:
- It gives a very simple usage to the developer;
- It watches “*.config” files and applies modifications without restarting the application;
- It can go independently from app.config/web.config files.
Implementation
First, we need to create a new class inheriting from System.Configuration.ConfigurationSection
in order to define a custom configuration section. Then, we need to create a utility class that will manage the configuration file via the FileConfigurationSource
class.
Here is the sample implementation:
public class CustomSection : ConfigurationSection
{
[ApplicationScopedSetting]
[ConfigurationProperty("applicationName ",
DefaultValue = "My Application Default Name", IsRequired = true)]
public String ApplicationName
{
get { return (String)this["applicationName"]; }
set { this["applicationName "] = value; }
}
}
public sealed class CustomSettings
{
#region singletone
private static CustomSettings _instance;
private static readonly object _instanceSync = new object();
private static CustomSettings Instance
{
get
{
if (CustomSettings._instance == null)
{
lock (CustomSettings._instanceSync)
{
if (CustomSettings._instance == null)
{
CustomSettings._instance = new CustomSettings ();
}
}
}
return CustomSettings._instance;
}
}
#endregion singletone
private FileConfigurationSource fileConfigurationSource;
private CustomSettings()
{
string settingsPath = String.Concat(AppDomain.CurrentDomain.BaseDirectory,
"Custom.config");
CustomSettings.fileConfigurationSource =
new FileConfigurationSource(settingsPath);
}
public static CustomSettings Current
{
get {return CustomSettings.Instance.fileConfigurationSource.
GetSection("customSettings") as CustomSection;}
}
}
Here is the sample "*.config" file source:
<configuration>
<configSections>
<section
name="customSettings"
type="Sample.Config.CustomSection, Sample.Config,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
allowDefinition="Everywhere"
allowExeDefinition="MachineToApplication"
restartOnExternalChanges="true" />
</configSections>
<customSettings
applicationName="My Application"
>
</customSettings>
</configuration>
Here is the sample usage from the source code:
string appName = CustomSettings.Current.ApplicationName;
As a conclusion, I would like to say that it is a good and quite simple solution. Also, it perfectly matches to standalone application usage.
Database server side configuration storage
Storing application settings in a configuration file is senseless for distributed applications (for example, a web application in a web farm). In that case, it is valuable to store settings in a single place. The most useful approach is storing settings in a backend database. But in this case, we need to solve the problem of serializing different types of settings into strings or binary. I would like to describe this problem in more detail.
All primitive types have static methods for parsing their values from strings. And, there is special class Convert
which allows converting to string and back any type that implements the IConvertible
interface. The only one rule that must be considered – it needs to store all the settings in invariant culture.
Sometimes, it is required to have more complex settings that are implemented as dedicated classes. Also, there is not much problem to serialize them into binary or XML content. (We need to mark the class with a Serializable
attribute in order to serialize its instances into binary). Also, you may want to implement a custom serialization mechanism in order to avoid performance drawbacks of the default XML serialization functionality. By the way, it should be noted that caching brings perfect performance gain to this solution (please see my article: caching implementation receipt).
Afterwards, the usage of such settings management can look like:
DateTime initialDate;
if (ServiceFacade.SettingsService.TryGetSetting<datetime />("INITIAL_DATE",
out initialDate))
{
}
Or, we can make it as simple as:
DateTime initialDate = ServiceFacade.SettingsHelper.InitialDate;
Please refer to the attached source code for details.