Configuration with IConfigurationProviders

In the first topic we used a default configuration which uses standard .NET configuration files used for the application. It's easy, but offers only the default functionality. If you want to customize what configuration type is used, enable encryption of values or otherwise customize operation you can explicitly configure a specific IConfigurationProvider to use and pass to the Initialize() method.

The following providers are available:

  • ConfigurationFileConfigurationProvider
    Stores information in standard .NET .config files, like web.config, app.config or possibly in externally linked .config files. This is the most common configuration file format for typical applications. One big advantage of .config files is that especially in Web apps .NET can detect changes to the file and restart applications to reload settings automatically. This is the default implementation used when Initialize() is called with no parameters in its default implementation.

  • XmlFileConfigurationProvider
    This format is based on XML serialization that stores configuration data in standalone XML files. Unlike the .config files these files aren't tracked by .NET so any changes to the files need be manually updated by reloading the configuration class.

  • SqlServerConfigurationProvider
    Stores configuration information in a single field of a database as an XML string. You can store multiple configurations in a single table by using a (int) Key value for each different configuration. Database configuration storage can be useful when configuration data might be shared across machines.

  • StringConfigurationProvider
    This format doesn't actually store configuration data at all, but simply provides serialization from the class to an XML string and loading up the class from an XML string. This can be useful if you have some custom storage mechanism and you don't want to create a custom provider. As long as your custom storage mechanism can accept a string you can use this provider with WriteAsString() to retrieve XML and Read(xml) to load from XML.

Overriding the Default Configuration Provider

If you need custom configuration on your configuration object, or you want to use configuration stores other than the default ConfigurationFileConfigurationProvider, it's a good idea to create the provider instantiation logic inside of the configuration class itself to avoid requiring a calling application to have to configure the provider.

To make your config object easy to instantiate, it's a good idea to override the default provider creation code to set up your configuration object with all the provider configuration applied so that the calling code doesn't have to muck with configuration logic. Ideally the configuration class should be self-configuring so that a call to Initialize() requires no parameters or only a token parameter to load configuration data, rather than full configuration logic.

It's very easy to create a custom default provider instantiation routine by overriding the OnCreateDefaultProvider() method in your configuration class. For example, here's a custom class that defaults to using the external XmlFile Configuration Provider:

public class XmlFileConfiguration : 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 Password { get; set; }
    public string AppConnectionString { get; set; }

    public XmlFileConfiguration()
    {
        ApplicationName = "Configuration Tests";
        DebugMode = DebugModes.Default;
        MaxDisplayListItems = 15;
        SendAdminEmailConfirmations = false;
        Password = "seekrit";
        AppConnectionString = "server=.;database=hosers;uid=bozo;pwd=seekrit;";
    }

    protected override IConfigurationProvider OnCreateDefaultProvider(string sectionName,
                                                                      object configData)
    {
        string xmlFile = "XmlConfiguration.xml";
        if (configData != null)
            xmlFile = xmlFile;

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

        return provider;
    }

    // Optional - provider overload with config file
    public void Initialize(string xmlFile)
    {
        base.Initialize(configData: xmlFile);
    }
}

Here the OnCreateDefaultProvider() method is implemented to handle creation of the default provider used when Initialize() is called without a provider parameter. This method simply encapsulates the provider creation logic that handles all the provider options required to create an instance.

The OnCreateDefaultProvider() method receives a sectionName and configData property both of which are passed down from the Initialize() method which also sports these parameters. This example allows optionally passing in the XML file via the configData parameter.

When using the database, Xml file or string providers you sometimes need to pass data to the provider like a filename or connection string. the configData parameter allows for arbitrary data to be passed to the provider creation code. Here the parameter is the Xml file name.

To make it really obvious that a filename can be passed I also created an optional overload of Initialize() which accepts a string parameter xmlFile which makes it more obvious what can or should be passed during initialization.

Using a non-default ConfigurationProvider

Typically, you just create a constructor with a default ConfigurationProvider as shown in the previous example, and that's all you need.

However, in case you do need to use mutliple configuration stores or switch stores dynamically at runtime, you can also pass in a customized ConfigurationProvider explicitly.

var provider = new SqlServerConfigurationProvider<ApplicationConfiguration>()
{
    PropertiesToEncrypt = "MailServerPassword,ConnectionString",
    EncryptionKey = "secret",
    ConnectionString = "DevSampleConnectionString",
    Tablename = "Configuration",
    Key = 1
};

var configuration = new ApplicationConfiguration();           
configuration.Initialize(provider);

this.Page.Title += " - " + configuration.ApplicationTitle;

Here we simply create any of the stock providers and configure them explicitly and then pass them as a parameter to the Initialize() method.

Configuration Provider Examples

The following are a few examples that demonstrate configuraiton of the various configuraiton providers available.

Each provider inherits from ConfigurationProviderBase which includes the following properties:

  • PropertiesToEncrypt
  • EncryptionKey
  • ErrorMessage

The base also provides default implementations of both static and instance methods for Read(),Write(), WriteAsString() operations.

ConfigurationFileConfigurationProvider
This is the most common provider and the one we recommend using unless there's a specific need to use one of the others. The advantage of this provider is that its behavior is directly integrated with the .NET configuration classes and so provides all the benefits such as change tracking in Web apps to you without any additional code.

var provider = new ConfigurationFileConfigurationProvider<ApplicationConfiguration>()
{
	PropertiesToEncrypt = "MailServerPassword,ConnectionString",
	EncryptionKey = "secret",
	ConfigurationSection = "ApplicationConfiguration",
	ConfigurationFile = Server.MapPath("~/ApplicationConfiguration.config") 
};

var configuration = new ApplicationConfiguration();
configuration.Initialize(provider);

The key properties specific to configuration files are ConfigurationSection and ConfigurationFile. If the file is not specified the stock .NET .config file - web.config or app.config - is used. If ConfigurationSection is not provided the default appSettings section is used.

XmlFileConfigurationProvider
This provider creates XML output files using standard .NET serialization. Rather than going through the .config files plain XML serialization/deserialization is used to write output to disk. Otherwise the behavior of this provider is nearly identical to the ConfigurationFileConfigurationProvider.

var provider = new XmlFileConfigurationProvider<ApplicationConfiguration>()
{
	PropertiesToEncrypt = "MailserverPassword,ConnectionString",
	EncryptionKey = "_secretive_",  
	XmlConfigurationFile = Server.MapPath("~/MyAppConfiguration.xml")
};

var configuration = new ApplicationConfiguration();
configuration.Initialize(provider);

The key property for the XmlFileConfigurationProvider is XmlConfigurationFile which determines the location on disk.

SqlServerConfigurationProvider
The SQL Server configuration provider stores configuration information in a single database field as an XML value. The provider works with SQL Server and Sql Server Compact 4.0.

The following demonstrates using SQL Server:

var provider = new SqlServerConfigurationProvider<ApplicationConfiguration>()
{
    ConnectionString = "Data Source=.;Database=DevSamples;integrated security=true;",    
    Tablename = "ConfigData",
    Key=1, // multiple keys can be used for multiple configurations
    PropertiesToEncrypt = "ConnectionString,MailServerPassword",
    EncryptionKey = "SUPERSECRET"
};

var configuration = new ApplicationConfiguration();
configuration.Initialize(provider);

and using SQL Server Compact 4.0. Note that you have to specify the ProviderName property explicitly.

var provider = new SqlServerConfigurationProvider<ApplicationConfiguration>()
{
    ConnectionString = "Data Source=|DataDirectory|\\applicationDb.sdf;",
    ProviderName = "System.Data.SqlServerCe.4.0", // only needed for non-SQL server
    Tablename = "ConfigData",
    Key=1, // multiple keys can be used for multiple configurations
    PropertiesToEncrypt = "ConnectionString,MailServerPassword",
    EncryptionKey = "SUPERSECRET"
};

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

The SqlServerConfigurationProvider will automatically create the table for storing configuration data if the connection has rights to do so.

The provider should also work with most other kinds of SQL backends, but you'll have to create the table manually. The structure for the table is:

CREATE TABLE [ConfigData]   ( [id] [int] , [ConfigData] [ntext]);

StringConfigurationProvider
This provider is a limited provider in that it doesn't actually persist to a store, but rather just serializes and deserializes from XML using the AppConfiguration's Read() and WriteAsString() methods.

To configure the string provider is the same as the other providers:

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

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

Here the initial data used is provided in the InitialStringData property. This is an XML string of a serialized configuration object.

You can also use Read() and WriteAsString() to serialize configuration data.

Note that the StringConfigurationProvider() is not really necessary in most cases, since all providers support Read() from string and WriteAsString().


© West Wind Technologies, 2019 • Updated: 12/19/15
Comment or report problem with topic