For .Net projects that have multiple developers, configuration differences can be a real problem. For this post, we’ll use the example of connection strings, but it could just as easily be a directory location, or some other difference. Let’s say that we have two developers, one is using SQL Server, while the other is using SQL Server Express. A minor difference in configuration. The first developer needs to list a DataSource of “.” or “localhost”, while the second developer’s DataSource is something like “.\SqlExpress” or “localhost\SqlExpress”.
Note, for the purposes of this discussion, I’ll refer to some git terminology, as it’s my preferred source control tool, but this could just as easily apply to TFS, subversion, mercurial, etc.
Some developers will put the most common version in their web.config, and the developers in the minority have to change their file without checking in, and regularly undo and redo that process in order to get latest if their are other web.config (or app.config) changes.
To avoid this, some teams don’t check in the web.config file. They check in something like web.config.sample which has the default settings, and you make a local copy called web.config that is not registered with source control. You can make any appropriate changes without causing conflicts. Anytime you get latest and see a web.config change, you’ll want to use your favorite merge tool to pull any necessary changes into your web.config. Less work than the previous version, but more manual merging.
I like to recommend a 3rd method, that uses a lesser known piece of web.config capability. Most config sections allow a configSoure attribute to specify an external config file.
So in the case of the connection string differences, the web.config would get checked into source control, and it’s connection string section would like like the following:
And then the connection.config file is treated like the second method above. There is a connection.config.sample file in source control that shows all the connection strings you need to have with sample connection info. Like follows:
<?xml version="1.0" encoding="utf-8" ?>
connectionString="Data Source=.;Initial Catalog=SomeDB;Integrated Security=True;"
Additionally, we have a rake task (could be msbuild, maven, .bat, etc) that helps you initialize the project upon first checkout. One of the things it does, is copy that file from connection.config.sample to connection.config. And our .gitignore file on the project, tells git to ignore connection.config. Now you only need to change your DataSource and are ready to go. And the web.config can change without the need to change your connection.config file. The only time that should change is when you add, remove, or rename a connection string.
This same idea can be used for Elmah config, SMTP config, etc. For example, in development, we have email go to file, and different developers use different directories to store the mail. This scheme handles it.
Lastly, this same scheme can largely handle the differences we have with staging and production environments. Since the differences in web.config from the development branch to the stage and production branch are minimal, merging is pretty painless. And those external config files are a one-time setup on the server.
Consider this pattern for your projects, and let me know what you think. Either in the comments below or at @thoolihan. And if you find any room for improvement or have other feedback, please pass it along.