My question is about working with standard .NET configuration objects and custom configuration elements as well, (which one can define by extending the System.Configuration.ConfigurationSection
class). We usually obtain these from the System.Configuration.ConfigurationManager
class's methods, GetSection(...)
being an example.
The loaded configuration object appears to be a merged configuration object containing the setup present in the application config file (the the app.config or web.config file which a developer may have created) and what is defined in the machine.config file (the latter coming with the .NET Framework installation).
So, we can assume that the configuration is loaded in hierarchical manner with the machine.config first, and any user-defined configuration overlaying that default setup, and could be looked at like this:
My goal is to create multiple layers of configuration, so that there might be other config files between (and if possible, after) the machine.config and the app.config file:
Update
The point with that is - if I have defined the configuration section in both custom.config and app.config, I need to get a merged version of both configs when I call ConfigurationManager.GetSection("MyCustomSection")
. Ideally, it will be great if I am able to perform merging as described in this MSDN article or use Wayback machine link
Normally, I would write my own configuration manager class and will try to get as far as I could to get the desired result, but assuming the .NET framework has this working for machine.config and app.config, I thought I might benefit from the built-in functionality of the framework. In addition, I do not know how to manually trigger such merging, if I am indeed supposed to resort to a config manager implementation of my own.
So, is it possible to leverage the built-in mechanisms of configuration section/element merging with custom configuration files? I am especially interested in developing and supporting this for custom configuration sections. The System.Configuration
namespace contains base objects to build configuration section and elements, and those allow some settings related to the merging (like setting the appropriate ConfigurationElementCollectionType
for example). Are these related to only merging with machine.config (or multiple layers of web.config files in a web application), or is it possible to manually trigger the merging of pre-loaded config files? I am trying to avoid having to support custom merging in any of my custom configuration objects and probably forget about supporting the existing settings from the System.Configuration...
Update
There is an important clarification to I'd like to make, in response to the existing answers and comments. I am capable of loading the ConfigurationSection
objects from the current application setup (app.config / web.config) and from a physical file that is my custom.config. I need to know if there is a chance to merge these objects without resorting to reflection and property-by-property comparison, by some built-in means in the framework.
As silver has pointed out, a well configured ExeConfigurationFileMap
could do the job, at a certain cost.
I have taken his example and made a working version of it.
Here are the two config files I have merged for my test purposes:
custom.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="custom" type="..." />
</configSections>
<custom>
<singleProperty id="main" value="BaseValue" />
<propertyCollection>
<property id="1" value="One" />
<property id="4" value="Four" />
</propertyCollection>
</custom>
</configuration>
app.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="custom" type="..."/>
</configSections>
<custom>
<singleProperty id="main" value="OverriddenValue" />
<propertyCollection>
<property id="1" value="OverridenOne" />
<property id="2" value="Two" />
<property id="3" value="Three" />
</propertyCollection>
</custom>
</configuration>
And I used the following code to test the merged setup:
var map = new ExeConfigurationFileMap();
map.MachineConfigFilename = PathToCustomConfig;
map.ExeConfigFilename = PathToAppConfig;
var configuration = ConfigurationManager.OpenMappedExeConfiguration(
map,
ConfigurationUserLevel.None);
var section = configuration.GetSection("custom") as CustomConfigSection;
Assert.IsNotNull(section);
Assert.AreEqual(section.SingleProperty.Value, "OverriddenValue");
Assert.AreEqual(section.PropertyCollection.Count, 4);
// Needed to map the properties as dictionary, not to rely on the property order
var values = section.PropertyCollection
.Cast<SimpleConfigElement>()
.ToDictionary(x => x.ID, x => x.Value);
Assert.AreEqual(values["1"], "OverridenOne");
Assert.AreEqual(values["2"], "Two");
Assert.AreEqual(values["3"], "Three");
Assert.AreEqual(values["4"], "Four");
map.MachineConfigFilename = PathToCustomConfig;
I assume I am removing any values that are set up by the real machine.config
file. This could be error-prone and should be avoided for web applications, as most of them rely on what's in the real machine.config
app.config
will be named when the code is compiled (usually AssemblyName.exe.config)I am still in the process of refining the technique, thus I will return to update this post once done.