KyKo
KyKo

Reputation: 392

Enterprise Library 5 Hybrid Configuration

We are using Enterprise Library 5.0 and would like to use the Logging application block to write log/trace messages to the Database. Doing all of the configuration in the web.config file works like a champ.

However, when the application starts up we need to be able to specify the database connection string that the logger uses dynamically. We thought that we might be able to take a hybrid approach by using the Ent Lib 5.0 Fluent API to register the connection string programmatically and then merge that with the configuration values from the web.config. This would allow us to be able to reconfigure how/where the trace messages are written without having to change the code.

This is what we have tried:

var dynamicConnectionString = "..."  // value determined elsewhere

var builder = new ConfigurationSourceBuilder();
builder.ConfigureData()
    .ForDatabaseNamed( "TestDB" ).ThatIs.ASqlDatabase()
    .WithConnectionString( dynamicConnectionString );

var configSource = new SystemConfigurationSource();
// the line below throws an ArgumentException with the message
// 'Cannot add a ConfigurationSection with the same name that already exists'
builder.UpdateConfigurationWithReplace( configSource );
EnterpriseLibraryContainer.Current = EnterpriseLibraryContainer.CreateDefaultContainer( configSource );

In the web.config file for our test project we only define the loggingConfiguration section as follows:

<loggingConfiguration ...>
    <listeners>
        <add databaseInstanceName="TestDB" ... />
    </listeners>
    <formatters>...</formatters>
    <categorySources>...</categorySources>
    <specialSources>...</specialSources>
</loggingConfiguration>

If I inspect the builder object in the debugger, it only has 1 section defined: a connectionStrings section that contains a single connectionString entry with the values I specified through code. The web.config file doesn't contain a connectionStrings section at all.

Ironically, if I use the Immediate/Watch Window and inspect System.Configuration.ConfigurationManager.ConnectionStrings, it reports that there is 1 connection already defined... the default ("data source=.\SQLExpress;Integrated Security=SSPI;AttacheDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true") connection.

If I add <connectionStrings><clear /></connectionStrings> to clear the inherited values, when I debug again I still get the same exception as before and VS notifies me that the web.config file has been updated (if I reload the file, the <connectionStrings> section has been removed).

What am I missing here! This can't be that hard!

Upvotes: 0

Views: 160

Answers (1)

KyKo
KyKo

Reputation: 392

After thinking about this over the weekend and doing a little more digging, I found a Blog Post that helped me resolve my issues. This is how it is working for me:

var builder = new ConfigurationSourceBuilder();
// Configure the dataSource (connection string)
builder.ConfigureData()
    .ForDatabaseNamed( "TestDB" )
        .ThatIs.ASqlDatabase()
        // this would be determined at runtime; not statically defined
        .WithConnectionString( @"Data Source=.\SQLExpress;Initial Catalog=Logging;Integrated Security=True" )
    .AsDefault();

// create a new config source
var configSource = new DictionaryConfigurationSource();
builder.UpdateConfigurationWithReplace( configSource );

IUnityContainer container = new UnityContainer();

// load the default configuration information from the config file
// i.e. ConfigurationSourceFactory.Create()
// and add it to the container
container.AddNewExtension<EnterpriseLibraryCoreExtension>();

// create a configurator to use to configure our fluent configuration
var configurator = new UnityContainerConfigurator( container );
EnterpriseLibraryContainer.ConfigureContainer( configurator, configSource );

// Use the configured container with file and fluent config as the Enterprise Library service locator
EnterpriseLibraryContainer.Current = new UnityServiceLocator( container );

// Write a log entry using the Logger facade
LogEntry logEntry = new LogEntry
{
    EventId = 180,
    Priority = 1,
    Message = "Message",
    Categories = { "AccessAudit" }
};

Logger.Write( logEntry );

Hope this helps someone else in the future.

Upvotes: 1

Related Questions