In my current project, we have a requirement to store some of the application settings in separate files from web.config. Some application settings will change often enough that we'd like to export them from a forever-behind-the-firewall database to a file we can drop into the public website. On the other hand the basic web.config settings will rarely change, and it could really mess up the application if the autogen'd settings somehow stomped an important configuration value in web.config. Keeping these two kinds of settings in separate files helps make this approach viable.
As it turns out, this particular application uses three different mechanisms for referencing settings in an external file, so I've had a chance to compare and contrast the approaches.
1. <appSetting>'s file= attribute.
2. Any config section's configSource= attribute.
3. A custom config section of type System.Configuration.AppSettingsSection. This is essentially the same mechanism as #1, but you can create as many separate configuration files as you need using custom sections.
<appSetting>'s file=
The <appSetting> file mechanism is both simple and flexible, and probably "enough" for most ASP.NET 2.0 applications that need an external settings file. The AppSettingsSection class allows supports loading settings from both an external file as well as declaring them inline in web.config:
In web.config:
<appSettings file="moresettings.config">
<add key="first" value="inline settings are loaded before external ones" />
</appSettings>
In moresettings.config:
<appSettings>
<add key="second" value="another setting" />
<add key="third" value="yet another setting" />
</appSettings>
Notes:
- the ACLs of the moresettings.config file must allow the ASP.NET application to read it
- the root node of the moresettings.config file must be <appSettings>
- key/value pairs declared inline in web.config appear first in the resulting NameValueCollection
Using the settings in code is easy:
using System.Configuration;
...
string first = ConfigurationManager.AppSettings["first"] as string;
When you access appSettings in code, all of the settings are members of the same collection despite being declared in separate files. Your application could use this mechanism alone to segregate specific application-scoped settings to another file.
<urlMapping>'s configSource=
The configSource attribute can be used to specify an external source file for any ASP.NET 2.0 config section. Unlike the file attribute, there's no merging of config settings between web.config and the external configuration file; you must move the entire section to a separate file. The section tag (in this case <urlMappings>) must be the root element of the external file.
In web.config:
<urlMappings configSource="friendlyurls.config" />
In friendlyurls.config:
<urlMappings>
<clear />
<add url="~/Home.aspx" mappedUrl="~/Default.aspx?tab=home" />
</urlMappings>
Custom config section using System.Configuration.AppSettingsSection
There is plenty of documentation on MSDN for creating custom config section handlers in code, and in cases where you want to parse custom XML tags the full metal approach makes sense. But if you just need another group of key/value pairs it's much simpler to use the existing System.Configuration.AppSettingsSection class. This is the same class used for <appSettings> so it has the added benefit of permitting you to merge inline and external settings into a single KeyValueConfigurationCollection at runtime.
In web.config:
<configSections>
<section name="regions" type="System.Configuration.AppSettingsSection, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" requirePermission="false" />
</configSections>
<regions file="regions.config">
<add key="BE" value="Europe" />
</regions >
In regions.config:
<appSettings>
<add key="US" value="North America" />
<add key="CA" value="North America" />
</appSettings>
Reading the settings from a custom AppSettingsSection is more work than from the default AppSettings section. And web.config heirarchies and the WebConfigurationManager.OpenWebConfiguration() method are just flexible enough to make grabbing the right instance of your web.config a little tricky. I found the documentation and sample in the ASP.NET Quickstarts helpful in decyphering the options. Here's some code that reads settings from a custom AppSettingsSection in the current application's root web.config:
using System.Configuration;
using System.Diagnostics;
using System.Web;
using System.Web.Configuration;
...
// Determine web path of the application's web.config
string path = HttpContext.Current.Request.CurrentExecutionFilePath;
path = path.Substring(0, path.LastIndexOf('/'));
if (path.Length == 0)
path = "/";
// Open the config section as an AppSettingsSection
Configuration rootWebConfig = WebConfigurationManager.OpenWebConfiguration(path);
AppSettingsSection regionSection = rootWebConfig.GetSection("regions") as AppSettingsSection;
if (regionSection != null)
{
// Get the appSettings key/value pairs collection
KeyValueConfigurationCollection regionSettings = regionSection.Settings;
foreach (KeyValueConfigurationElement item in regionSettings)
{
Debug.WriteLine("key: " + item.Key.ToString());
Debug.WriteLine("value: " + item.Value.ToString());
}
}