Factoring Configuration

A little known attribute, configSource, enables some level of configuration factoring and splitting for the ever-growing web.config...

Its an odd feeling when you discover something in your own product, you didn't quite knew existed!

Theres a little known attribute called configSource, that can be specified on a section which allows the definition of the section to live in another actual file. Well, actually I had a vague recollection of it, from past work around IIS7 and config, and went hunting for it this morning in the context of discussing a new feature that is dependent on some new configuration entries. This is especially relevant given some of the complaints around the use of configuration in various ASP.NET Ajax features.

Here's an example scenario... the profile feature allows me to specify a bunch of named properties that should be managed per-user, along with type information and other metadata. This information currently goes within the <profile> section within <system.web> in web.config. This always struck me as odd. The profile settings are first and foremost defining database schema, application logic (by virtue of generating a strongly-typed class), and only then is it about configuration in a classic sense. I've always thought it would be better if this information was in a separate .profile kind of file. Well, with configSource, you can do just that... almost!

For example, here's what I can put into my web.config:

...
  <system.web>
    ...
    <profile configSource="profile.config" />
    ...
  </system.web>
...
Once I've done that, I can now add a profile.config file into my web site as follows:
<profile>
  <properties>
    <add name="Name" type="String" />
    <add name="Age" type="Int32" />
  </properties>
</profile>
Everything continues to work as before. Essentially I've cut out the actual profile section from web.config and moved it into a separate file, which might help manage config a bit better, simply by splitting it out, as well as perhaps make me a bit happier that profile information isn't mixed with configuration! Note that you should probably still name these additional files as .config, so they aren't served out. The MSDN documentation for this property has an example that uses a separate .xml file - bad choice.

This is essentially feature that provides include semantics. However, looking at this makes me wish we had a feature that provided merge, so I could for example, define the profile providers in web.config, and just the properties in profile.config. Configuration is already quite complex with merge happening across different levels in the hierarchy (machine, site, app, folder, file), and this would be a merge at a single level, so its hard to say whether this will happen any time soon. If it did exist, the merge-like feature would have allowed us to actually define an Ajax.config file which could be added to a site to Atlas-enable the site for example, rather than having to merge config settings all over the place in the single web.config file. For example, to enable ASP.NET Ajax, there is a new system.web.extensions section that could go into a separate file. In addition there are couple of required entries in the httpModules and httpHandlers sections. No doubt, this limits the feature a bit, but still useful in some limited scenarios.


[ Tags: ]
Posted on Wednesday, 4/25/2007 @ 11:37 AM | #ASP.NET


Comments

10 comments have been posted.

Joe

Posted on 4/25/2007 @ 12:45 PM
Can you post full before and after files? I am unable to start debugging etc etc after trying this.

Ryan Montgomery

Posted on 4/25/2007 @ 2:25 PM
We use this all the time for our build scenarios. For example we setup the default to be like:

<connectionStrings configSource="connectionStringsLocal.config" />

and then in our publish to our Dev and QA boxes the value gets changed to

<connectionStrings configSource="connectionStringsDev.config" />
or
<connectionStrings configSource="connectionStringsQA.config" />

so in each file they point to our dev and qa databses.

The same applies to appSettings however you need to use the "file" attribute like so:
<appSettings file="appSettingsLocal">
...
</appSettings>

which on build gets changed to file="appSettingsDev" or file="appSettingsQA" which allows us to change the sites settings for each environment.

John

Posted on 4/25/2007 @ 3:00 PM
You can do the merge from code, however.

Chad

Posted on 4/25/2007 @ 6:10 PM
As soon as I read your post I too recalled have "known" about this earlier. Thanks for the reminder!

Jon Gallant

Posted on 4/25/2007 @ 6:53 PM
There is also an option that prevents an application restart when an external config file changes. The RestartOnExternalChanges property is by default true, but if you set to false, then changes to that external file won't cause the application to restart.

See more about it here: http://msdn2.microsoft.com/en-us/library/system.configuration.sectioninformation.restartonexternalchanges.aspx

Brennan Stehling

Posted on 4/25/2007 @ 7:39 PM
You can also us the ReplaceConfigSections task with MSBuild which is a part of the Web Deployment Project. This task is typically tied to the build process but you can load just the ReplaceConfigSections task independently and use it in a post build scenario.

<UsingTask
TaskName="ReplaceConfigSections"
AssemblyFile="$(MSBuildExtensionsPath)\
Microsoft\WebDeployment\v8.0\Microsoft.WebDeployment.Tasks.dll"/>

I am not sure if that XML will make it as a comment. I may post this in more detail on my blog soon.

Arne Claassen

Posted on 4/25/2007 @ 10:28 PM
I came across configSource a while back, noticing it on <connectionStrings> in 2.0. The problem I have with configSource over the file attribute is that the child config has to be in the same or a child directory (i.e. no "../foo.config"). I think that's unfortunate. I usually have my config files outside the apps tree so that I can share common configs among a number of apps and so that it doesn't accidentically fall under source control. After all the point of the config is to have an external data source for the things that vary from installation and installation and might be changed without code changes.

So most of the time I still create my own custom config section handlers, when I'd much rather just use the built in facilities.

Giorgio

Posted on 4/27/2007 @ 10:20 PM
This is a (related) feature request - it would be really nice to be able to make the web.config point to something other than a file (for example, a URL.) This would allow centralization of application configuration across the enterprise...

Chris Pietschmann

Posted on 4/30/2007 @ 12:15 PM
To get around th sissue of the segmented configuration files being required to be within the root or subfolders of your site; I was thinking you could just inherit from the System.Configuration.ConnectionStringsSection object and implement your own logic (and do the same for other config sections you need to tweak the functionality for.) But, there's one problem, the System.Configuration.ConnectionStringsSection is a Sealed class. I haven't checked, but I'm assuming all the other built in config section handlers are also Sealed. That's too bad; since it would be really cool to be able to override their functionality if they didn't quite meet your needs 100%. Future version, please??

Rick

Posted on 5/24/2007 @ 1:13 AM
Thank you - this will be useful. As a feature request it would be even better if this worked for section groups too.
The discussion on this post has been closed. Please use my contact form to provide comments.