jmlane
jmlane

Reputation: 2198

Can `System.Configuration.ConfigurationManager.ConnectionStrings` be updated with non-default configuration file values?

I am trying to access a set of connection strings from an arbitrary configuration file provided at runtime by way of the ConfigurationManager.ConnectionStrings static property. Application code expects the connection string to be in this collection and I need to provide a new value without editing the default configuration file.

I have determined that I can use System.Configuration.ConfigurationManager.OpenMappedExeConfiguration to load connection strings from an arbitrary configuration file by using System.Configuration.ExeConfigurationFileMap, e.g.:

using System.Configuration;

var config = ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap{ExeConfigFilename = 'some.config'}, ConfigurationUserLevel.None);

config.RefreshSection(config.ConnectionStrings.SectionInformation.SectionName);

In this context, I'd expect to be able to access the connection strings loaded from some.config from the static ConfigurationManager.ConnectionStrings property but this seems to hold only what was available in the application configuration defaults.

Is it possible to mask or copy into the default configuration to update the value of the static ConfigurationManager.ConnectionStrings property? Alternatively, is any way to redefine the default configuration to a new configuration file defined at runtime, hopefully leading to the desired end result?

Upvotes: 0

Views: 743

Answers (2)

jmlane
jmlane

Reputation: 2198

An interesting reflection workaround I discovered allows changing the non-public System.Configuration.ConfigurationElementCollection.bReadOnly property of System.Configuration.ConfigurationManager.ConnectionStrings by using reflection:

using System;
using System.Configuration;

var connectionString = "...";
var connectionStringSetting = new ConnectionStringSettings("OrionDB", connectionString);
var field = ConfigurationElementCollection.GetField("bReadOnly",
    Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Instance);
var connectionStrings = ConfigurationManager.ConnectionStrings;
field.SetValue(connectionStrings, false);
connectionStrings.Add(connectionStringSetting);

This gave me the desired behaviour while not necessarily the intended use of the static ConfigurationManager properties.

Upvotes: 0

Scott Hannen
Scott Hannen

Reputation: 29207

The short answer is no. The ConnectionStrings and AppSettings properties of ConfigurationManager are just for convenience to read from the default configuration. You can load other configurations, but you can't change the behavior of those methods.

If this Configuration is properly loaded:

var config = ConfigurationManager.OpenMappedExeConfiguration(
    new ExeConfigurationFileMap{ExeConfigFilename = 'some.config'}.
        ConfigurationUserLevel.None);

Then you can get the connection string from there.

var connectionString = config.ConnectionStrings.ConnectionStrings["connectionName"]
    .ConnectionString;

A part of the answer is not to use ConfigurationManager or Configuration from deep within your classes. You can either use dependency injection, or, worst case scenario, create your own static class to use instead of ConfigurationManager. But this is a perfect example of why you don't want a class accessing this directly, because you can't change its behavior.

Upvotes: 1

Related Questions