Willem's...

{rue if I mellow}

  Home  |   Contact  |   Syndication    |   Login
  25 Posts | 0 Stories | 129 Comments | 52 Trackbacks

News

Archives

Post Categories

Businessware Architects

XML-FX.COM

Monday, November 13, 2006 #

The .NET 2.0 System.Configuration.dll provides a much more sophisticated (and complex) set of classes that access and modify application .config files, than compared to the functionality in .NET 1.x.

However, most often, the requirement is still to provide simple access to and from the key-value pairs in the appSettings section as before.

This post establishes a very simple abstract base-class that provides a simple binding to the appSettings section that requires no code to be written in the sub-class. It provides a Load method that is called in the  instance constructor. The Load method uses reflection to determine the public properties of the derived class. For each of these properties, the key-value instance in the appSettings is accessed, the value is read and converted from a string to the required property type, and the property value updated. There are two restrictions to this action:

  • The correct value type must be able to be instanced by the System.Convert.ChangeType method and converted from a System.String, so the type should be a simple (primitive) type such as a string or int, etc.
  • The property should be a simple value type which is not an array. The Load method checks for this using the System.Type.IsArray property, and ignores the property if the value is true.

Of course, it can be argued that if the application setting value does not adhere to those restrictions, it should not be stored in the appSettings section in the first place.

In the instance destructor, the Save method is called. Again using reflection, for each public property which is not an array, the key-value of the appSettings section is accessed and updated with the current value of the property. Note that the value is changed to a System.String, which is in keeping with the restrictions mentioned above. Once the settings are updated, they are saved back to the .config file and then reloaded, to ensure correct updating subsequently.

Note that the Load and Save methods are public so they can be called from external code at any time. They are also virtual so that they can be overridden by the derived class if required.

The C# code for the base-class is shown in Listing 1 below:

 

Listing 1: Application Settings Base Class
public abstract class AppSettings
{
  // Load the settings.
  public virtual void Load()
  {
    PropertyInfo[] properties = GetType().GetProperties();
    foreach (PropertyInfo property in properties)
    {
      if (!property.PropertyType.IsArray)
      {
        string appValue = ConfigurationManager.AppSettings[property.Name];
        if (appValue != null)
        {
          try
          {
            // Attempt to change the type from System.String to
            // the property type, and set the property value.
            property.SetValue(
              this,
              Convert.ChangeType(appValue, property.PropertyType),
              null);
          }
          catch {/*ignore*/}
        }
      }
    }
  }
  // Save the settings.
  public virtual void Save()
  {
    // Get the configuration file.
    System.Configuration.Configuration configuration =
      ConfigurationManager.OpenExeConfiguration(
        ConfigurationUserLevel.None);
    // Get the public properties of the class.
    PropertyInfo[] properties = GetType().GetProperties();
    // Save each property setting.
    foreach (PropertyInfo property in properties)
    {
      // Save if not an array type.
      if (!property.PropertyType.IsArray)
      {
        // Remove the setting if it exists.
        if (configuration.AppSettings.Settings[property.Name] != null)
        {
          configuration.AppSettings.Settings.Remove(property.Name);
        }
        // Add the setting.
        configuration.AppSettings.Settings.Add(
          property.Name,
          property.GetValue(this, null).ToString());
      }
    }
    // Save the configuration settings.
    configuration.Save(ConfigurationSaveMode.Modified);
    // Force a reload of the whole section.
    ConfigurationManager.RefreshSection("appSettings");
  }
  protected AppSettings()
  {
    // Load the settings when class instance is constructed.
    Load();
  }
  ~AppSettings()
  {
    // Save settings when instance is destroyed.
    Save();
  }
}

So how do you use it?

In Listing 2 is a test settings class. Note that the only requirement to get it all the work is to add the class inheritance reference. Now if your application creates an instance of the derived settings class, the .config file settings are loaded, if available. By simply destructing the instance (by normally letting it run out of scope), the settings are automatically saved for the derived class public properties. This also keeps working, whether you add or remove public properties to the derived class.

 

Listing 2: A test sub-class which is instantiable in an application.      
public class Settings : AppSettings
{
  private double doubleValue;
  public double DoubleValue
  {
    get { return doubleValue; }
    set { doubleValue = value; }
  }
  private decimal decimalValue;
  public decimal DecimalValue
  {
    get { return decimalValue; }
    set { decimalValue = value; }
  }
  private bool boolValue;
  public bool BoolValue
  {
    get { return boolValue; }
    set { boolValue = value; }
  }
  private int intValue;
  public int IntValue
  {
    get { return intValue; }
    set { intValue = value; }
  }
  private string stringValue;
  public string StringValue
  {
    get { return stringValue; }
    set { stringValue = value; }
  }
  private DateTime dateTimeValue;
  public DateTime DateTimeValue
  {
    get { return dateTimeValue; }
    set { dateTimeValue = value; }
  }
  public Settings() { }
}

Here is what the .config file looks like for this example:

 

Listing 3: The .config file showing the settings stored as keys.          
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <appSettings>
        <add key="DoubleValue" value="3.141592654" />
        <add key="DecimalValue" value="-100.01" />
        <add key="BoolValue" value="True" />
        <add key="IntValue" value="1024" />
        <add key="StringValue" value="The quick brown fox jumped over
           the lazy dog." />
        <add key="DateTimeValue" value="2006/11/13 12:34:56 AM" />
    </appSettings>
</configuration>

You can download the AppSettings class and a sample application from the link below: