I have standard logging, NHibernate, etc. configuration blocks in my app.config
and I'd like to extract them into a common XML file that can be included as a reference by all of my applications' app.config
files.
Is this possible?
Yes, you can use the configSource
attribute of the configuration block. All configuration blocks have this attribute - although it isn't documented.
See this article, all the way at the bottom, appendix B. I've also pasted the relevant section below:
Appendix B: including external configuration files
Despite all the greatness to be found in .NET 2.0's configuration features, there is one drawback. When working on a single project across multiple environments, managing configuration can become a nightmare. The process of managing multiple versions of a configuration file for multiple environments -- i.e. development, testing, staging and production -- at my current job involves manual comparisons of
.config
files whenever changes are deployed to one environment or another, with a manual merging process. I spent months trying to find a better way and eventually found one. Enter one of those oh-so beloved "undocumented" -- or in this case, just poorly documented -- features that Microsoft is so famous for:configSource
. I only came across this little gem when I was digging through the .NET 2.0 configuration source code with Reflector, wonderful little tool.Each configuration section, when parsed and loaded by the .NET configuration classes, is assigned a
SectionInformation
object. TheSectionInformation
object contains meta information about a configuration section and allows some management of how sections override each other when defined in a child config file (ASP.NET). For now, we will ignore the majority of what SectionInformation has to offer, save theConfigSource
property. By adding aconfigSource
attribute to the root element of anyConfigurationSection
, you can specify an alternate, external source from which the configuration settings will be loaded.<!-- SomeProgram.exe.config --> <configuration> <connectionStrings configSource="externalConfig/connectionStrings.config"/> </configuration> <!-- externalConfig/connectionStrings.config --> <connectionStrings> <add name="conn" connectionString="blahblah" /> </connectionStrings>
In the configuration file above, the
<connectionStrings>
section has been sourced from a file calledexternalConfig/connectionStrings.config
. All of the application's connection strings will be loaded from the specified file. Now that the connection strings are loaded from an external resource, it is a relatively simple matter to create aconnectionStrings.config
file in each environment at the same relative location. Hence, theexternalConfig/
part of theconnectionStrings.config
path. The beauty here is that we can define connection strings properly for each environment once. We do not have to worry about accidentally overriding those settings during a deployment where a config file was either merged improperly or not merged at all. This can be a huge boon when deploying changes in an application to a production environment, where it is critical that the correct database connection strings exist. The downfall of using theconfigSource
attribute is that it requires all configuration settings to be placed in the external file. No inheritance or overriding is possible, which in some cases makes it useless. All external configuration files used with theconfigSource
attribute must also reside in a relative child path to the main.config
file. I believe this is in regards to security concerns with storing the file in a relative parent path in a web environment.Something else to note is that the
<appSettings>
section has a better alternative to usingconfigSource
, called file. If you use the file attribute rather than configSource with the<appSettings>
section, you can define settings in both the root.config
file and in the referenced file. Settings from the root.config
file may also be overridden in the referenced file, simply by adding something with the same key. Sadly, the file attribute is only available on the<appSettings>
section and is not built into the configuration framework. It is possible to implement a similar attribute in your own configuration sections. This will be discussed in a future installment of advanced configuration topics, after several prerequisite installments ;).