Storing Configuration Settings in a File, String or SQL Server

The AppConfiguration class can be configured with custom configuration providers that allow storage of configuration information in different, non-config file based storage mechanisms. This mechanism allows for various additional formats that are provided as well as for you to extend with custom providers. The additional providers available are:

All three of these formats use XmlSerialization to serialize the configuration settings.

The following examples assume the following configuration class setup:

class MyConfiguration : Westwind.Utilities.Configuration.AppConfiguration
{
    public string ApplicationName { get; set; }
    public DebugModes DebugMode { get; set; }
    public int MaxDisplayListItems { get; set; }
    public bool SendAdminEmailConfirmations { get; set; }
    public string MailServer { get; set; }
    public string MailServerPassword { get; set; }

    public AutoConfigFileConfiguration()
    {
        ApplicationName = "Configuration Tests";
        DebugMode = DebugModes.Default;
        MaxDisplayListItems = 15;
        SendAdminEmailConfirmations = false;
        MailServer = "mail.MyWickedServer.com:334";
        MailServerPassword = "seekrity";
    }
}

If you simply instantiate this class and call initialize:

var config = new MyConfiguration()
config.Initialize();

it uses the ConfigurationFileConfigurationProvider and writes into a section called MyConfiguration in the standard config file.

Let's look how to use other providers:

XmlFileConfigurationProvider

The Xml file provider allows writing to file that is not in .NET configuration format and can have basically any structure. It uses XML Serialization so it's possible with this scheme to include nested sub-objects in the configuration class, which is not possible with standard config files that use plain key value pairs.

Stick with ConfigurationFileConfigurationProvider unless you need nested types
In general, unless you require a special configuration format that requires nested types we recommend you stick with standard .NET configuration files using the ConfigurationFileConfigurationProvider because it provides additional features such as configuration file change detection in Web apps.

To create an XML configuration provider:

var xmlFile = "XmlConfigurationFile.xml";

var provider = new XmlFileConfigurationProvider<XmlFileConfiguration>()
{
    XmlConfigurationFile = xmlFile,
    EncryptionKey = "ultra-seekrit",  // use a generated value here
    PropertiesToEncrypt = "Password,AppConnectionString"
    // UseBinarySerialization = true                     
};

var config = new MyConfiguration();
config.Initialize(provider);

// read value
int maxItems = config.maxDisplayListItems;

// write value
config.maxDisplayListItems += 2;

// write out to disk
config.Write();

The key property on the provider is the XmlConfigurationFile property which has to be set to specify the file to write to. This filename should be a fully pathed file in a Web application. In a local application you can just use a filename or relative filename which is relative to the current directory.

SqlServerConfigurationProvider

Like the Xml file provider the Sql Server provider uses XML Serialization that works through string serialization that is then stored in the database in a single field. The idea is that you have a single table with a specific structure that can hold one or more configuration records in an nText field of the database.

var provider = new SqlServerConfigurationProvider<DatabaseConfiguration>()
{
    ConnectionString = connectionString,
    Tablename = tableName,
    Key = 1,
    ProviderName = "System.Data.SqlServerCe.4.0",

    EncryptionKey = "ultra-seekrit",  // use a generated value here
    PropertiesToEncrypt = "Password,AppConnectionString"               
};

var config = new MyConfiguration();
config.Initialize(provider);

// read value
int maxItems = config.maxDisplayListItems;

// write value
config.maxDisplayListItems += 2;

// write out to disk
config.Write();

The database provider has a few options that need to be set.

  • ConnectionString
    You need to provide a connection string or connection string name of the database you want to write the data to. This should be SQL Server or SQL Express, but it likely will work with other providers as well.
  • Tablename
    You also need to provide the name of the table that settins are written to. If not specified the table default to ConfigurationSettings.
  • Key
    An optional key that allows you to have several providers write into the same table with different records. Defaults to 1.
  • ProviderName
    The name of the ADO.NET provider used. Defaults to the full SQL Server driver.

When first creating the configuration instance it'll write the record into the database.

Reading and Writing String Configuration Settings

You can also read and write string configuration settings using any of the providers or the limited StringConfigurationProvider. String retrieval and writing works only with the Read() method that supplies a string parameter, and the WriteAsString() method to write content.

// get some XML from application
string xml =  MemoryConfig.SettingsXml;

var provider = new StringConfigurationProvider<StringConfiguration>()
{
    InitialStringData = xml,
    EncryptionKey = "ultra-seekrit",  // use a generated value here
    PropertiesToEncrypt = "Password,AppConnectionString",
};

var config = new MyConfiguration();
config.Initialize(provider);   // initial read

// read value
int maxItems = config.maxDisplayListItems;

// write value
config.maxDisplayListItems += 2;

// write out to disk
var newXml = config.WriteAsString();


// re-read some other XML 
config.Read(MemoryConfig.SettingsXml2);

// Change a value
config.DebugModes = DebugModes.ApplicationErrorMessage;

// write out the changed XML
newXml = config.WriteAsXml();

// do something useful with the XML - store on 
Repository.SaveCustomData(newXml)

If the InitializeStringData is empty or null nothing is loaded - it's as if the class was simply instantiated without an internal Read() operation. At that point you can then manually call Read() with a string to read in XML manually.

String retrieval is useful for applications that need to store output into non-supported storage mechanisms. By retrieving strings as an intermedia you can effectively write into any store that supports string based storage with a simple wrapper routine. This string support can also serve as a base implementations for custom providers you might implement yourself with the WriteAsString() and Read() overloads for string inputs available on the base ConfigurationProviderBase implementation.