Working with multiple conflicting config files

by matt 11. September 2006 23:26

One of the luxuries of working in a corporate environment is the uniformity (and I never thought I'd say that). You're in control of just about everything - you can ensure that all developers are using the same configuration. You can all use the same databases, the same web services, the same web sites.

Working on a distributed, open source project is entirely different. You're not in control of the environments being used. Different developers will have things set up differently. And all this is reflected in different web.config files.

There's just one teensy-weensy problem. The web.config file is under source control, which means there is only One True Copy. And if I change it to get my site working, I change it for everyone else, and break theirs.

Of course I'm talking about SingleUserBlog, and of course, this is a problem we've hit. We're all using a different config to each other, and I've already checked in a config file that won't work for everyone else.

So I've had a play around and I've come up with a solution. It's teetering dangerously close to over-engineered, but it also does the job nicely, and I learned a few things to the bargain.

Since SingleUserBlog uses Web Application Projects, it's an msbuild-based project. And the nice thing about msbuild-based projects is that you can edit the project file, add your own tasks in and Visual Studio will still quite happily run with it.

The idea is quite straightforward. Get rid of the web.config file. Create a default.config file that contains the default settings for the project - the one you'd be happy to release. Then, change the .csproj file to copy this file to web.config and use the ReplaceConfigSections task from the Web Deployment Projects add-in to replace any sections in the file with xml from external files.

The implementation is perhaps a little awkward, but it's not exactly horrible either. First, in the main .csproj file, import a MergeConfigFiles.targets file that does the heavy lifting. This new file needs to set up a UsingTask to include the ReplaceConfigSections task. It also needs to set up a few default properties, such as the name of the config files to copy ("default.config" to "web.config"). It then imports another .targets file, if it exists. This one is $(USERNAME)-MergeConfigFiles.targets. If it doesn't exist, the default.config file just gets copied, unchanged to web.config. If it does exist, it should be another msbuild project that simply sets up an ItemGroup containing ConfigReplacementFiles items. Each item points to a file that just contains xml that will replace a specific section in the web.config file. That section name is defined in the Section metadata item in the ConfigReplacementFiles item. The ItemGroup is fed into the ReplaceConfigSections task.

When a build is run, Visual Studio will copy across the default config file, then process this copy, replacing all the sections listed with the contents of all the files listed. If any of the files change, or if the default file changes, it gets rebuilt. It even deletes the web.config file on clean.

There are a couple of issues with this method, but I don't think any are showstoppers. It's perhaps not ideal to have to define this with an msbuild project file, but it's not difficult. Here's an example:

<Projectxmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <ConfigReplacementFilesInclude="compilation.config">
      <Section>system.web/compilation</Section>
    </ConfigReplacementFiles>
    <ConfigReplacementFilesInclude="authentication.config">
      <Section>system.web/authentication</Section>
    </ConfigReplacementFiles>
  </ItemGroup>
</Project>

Not exactly difficult. Another drawback is that if you change this .targets file, the changes are not reflected until the project is reloaded. Not ideal, but not major, either. Oh, and it will only work for web.config, too - the web deployment project task assumes that. Supporting app.config wouldn't be too tricky either, but would require a custom task.

One drawback that could actually cause problems is ensuring that your overrides don't override something new, or you only add new things to your overrides, but this is really just something you need to keep track of.

Another interesting drawback is that asp.net will automatically recreate the web.config file for you if it gets deleted. Somehow it knows to call the .csproj file and get it created correctly - well, mostly correctly. It did generate some things incorrectly while testing that, and it always did a full build after that anyway, so everything still worked correctly.

The only files that get into source control are default.config and the initial MergeConfigFiles.targets. The username based file doesn't get added, and neither do the local changes.

It might be easier to download an example and actually try it out. Let me know what you think.

Tags:

SingleUserBlog

Comments

9/13/2006 12:55:33 AM #

Nice one!

Hi Matt, this seems like a good path - well done for doing the research on it.  So basically, we just create a standard Web.config file which might use (say) the FileSystemProvider for SUB and the AccessProvider for ASP.NET API's and then allow each developer to create their own specific replacement file overrides.

Darren Neimke | Reply

9/14/2006 1:32:13 PM #

What about configSource?

Did you think about using the configSource attribute to externalize the configuration sections that could be customized? This way you'd just have to replace the external configuration files with the custom ones.

For example, in web.config you'd have:

  
  


and the actual configuration in the compilation.config and authentication.config files.

Fabrice | Reply

9/14/2006 3:28:44 PM #

configSource

Yeah, it's an option. But you can't provide a default set of values if you use configSource, so you'd need the target file to be always there. This means these files need to be checked into source control too, and then you're back where you started.

Matt Ellis | Reply

9/14/2006 6:40:23 PM #

Donnie Hale

Multiple Web.config files

I'm not sure why this is such a difficult issue. I have multiple Web.config files (Web.dev.config, Web.qa.config, Web.prod.config, etc.). Within VS, I use Web.dev.config (renamed, obviously, to Web.config).

When it's time to push to an environment, the build/stage scripts pick the right .config file for the targeted environment, run "aspnet_compiler", and deploy the results.

That's worked fine for me for numerous apps. What am I missing?

Donnie

Donnie Hale | Reply

9/14/2006 9:00:43 PM #

Multiple web.configs

We use MSBuild for our web application project too.  I agree with Donnie Hale though.  We have multiple configs (web.config.dev, web.config.testserver, web.config.prodserver, web.config.default).  MSBuild determines which one to deploy and copies it to the build folder.  Each config is under source control.  Works for us.

Walt Ritscher | Reply

9/14/2006 9:12:51 PM #

Multiple editors of web.config

Your approach works great for different environments (I use at work). The problem here is different in that we've got multiple people working on the one web.config at a time. E.g. I want to use a Microsoft Access based profile provider, and another guy wants to use a Sql Server one. If we have just one web.config file, it's going to be in source control. If I change it to use Access, I'll check that in and cause problems for the other guy using Sql Server.

I could check in multiple web.config files (web.matt.config, web.darren.config, etc) but then we don't have a default config file set (and this doesn't really scale for more developers).

Instead, I have one default.config file in source control, this is the default web.config file that will get used, and any changes will end up back in source control. If a developer wants to have a different config than the default, they just override the bits they want changed.

I think there are lots of ways around this problem - I was looking for a low friction, automated solution.

And I think perhaps I titled this post wrong - it's not "working with multiple conflicting config files" but "multiple people making conflicting changes on one config file"

matt | Reply

9/14/2006 9:22:20 PM #

Multiple web.configs

We use MSBuild for our web application project too.  I agree with Donnie Hale though.  We have multiple configs (web.config.dev, web.config.testserver, web.config.prodserver, web.config.default).  MSBuild determines which one to deploy and copies it to the build folder.  Each config is under source control.  Works for us.

Walt Ritscher | Reply

9/22/2006 9:34:56 PM #

Are comments broken?

Testing comments. Might have broken something...

Matt Ellis | Reply

4/4/2007 6:44:03 AM #

Dave Moyle

RE: Working with multiple conflicting config files

Your sample link is broken.

The type or namespace name 'RewritingStaticFileHandler' could not be found (are you missing a using directive or an assembly reference?)

Dave Moyle | Reply

4/4/2007 9:48:59 PM #

RE: Working with multiple conflicting config files

Ooops. Fixed the link - should be working now.

Thanks for letting me know!

Matt Ellis | Reply

6/19/2007 10:31:07 AM #

Rajesh

RE: Working with multiple conflicting config files

Good Article, but please make the font-color as black. It was difficult to read the article.

Thankyou

Rajesh | Reply

6/19/2007 2:40:19 PM #

RE: Working with multiple conflicting config files

Good point. Done! Now in lovely black on white.

Matt Ellis | Reply

5/5/2009 4:47:26 AM #

Brian Keith Photography

i think you have touched on some very good points about the web.config and the troubles of using it in different development environments.

Brian Keith Photography United States | Reply

1/6/2010 5:01:00 PM #

Rohan Cragg

I just asked a quesion on StackOverflow: "Can I use the ReplaceConfigSections task in a non-web config file?" if anyone thinks they may know, please come on over and answer... thanks.

http://stackoverflow.com/questions/2014370

Rohan Cragg | Reply

Add comment


(Will show your Gravatar icon)

biuquote
  • Comment
  • Preview
Loading



About the author

Something about the author

Calendar

<<March 2010>>
MoTuWeThFrSaSu
22232425262728
1234567
891011121314
15161718192021
22232425262728
2930311234

View posts in large calendar

RecentComments

Comment RSS

License

Creative Commons License
Except where otherwise noted, content on this site is by Matt Ellis and is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.

©2010 Matt Ellis