Handling web.config differences across multiple machines when using version control
I’m sure everyone has to deal with these situations, we check in our solution to source control and each dev machine will have its own resources for debugging, building and testing..
The most common being:
- xslt cloning with partial data
- How can I exclude SVN files from harvesting with heat (WiX)?
- Need XSL file to convert internal xml tests format to Junit format (xUnit Plugin for jenkins)
- Web server (IIS)
- Database (SQL)
The web server is easy to handle, each dev machine will have its own proj.user file to specify different debug information.
But connection strings for the app are stored in the web.config (which is under source control), ideally we don’t want the web.config to be ‘aware’, so having to do config sections where we delegate them to other config files (not under sc) wouldn’t be the best solution..
asp.net (.net?) already supports a model to have web.config inheritance, which would be an ideal scenario.. however this only works for directories.
It would be great if we could have
- web.config <– under version control
- web.machine.config <– not under version control
Of course I’m open for better suggestions of how people solve this problem.
Like.. maybe having:
- web.base.config <– under version control
- web.machine.config <– not under version control
And having a build script that creates a web.config by merging them?
Thanks in advance,
Looks like the next vs may have a way to handle this:
Possibly do’able with xml mass update today:
edit edit edit
Well its certainly possible to do with a simple xslt build task and a small transform that copied everything and intercepts certain properties.. just tried a proof of concept and this will save us lots of frustration, but the transformation file may be more than people are willing to accept.
Basically we store a Web.base.config in version control, and run it through the transform to generate the Web.config on a build event.
Seems like vs2010 will really help in terms of having a much more friendly version of this.
6 Solutions collect form web for “Handling web.config differences across multiple machines when using version control”
VS 2010 will provide you with a lot of control to manage web.config files for various configurations… Please check out.
One approach that I sometimes use is to break out environment-specific section into separate config file, that are usually excluded from deployment (except for the first time or if their structure change):
Example for connection strings:
The connections.config file (that is typically not included in the deployment; so it is unchanged):
<?xml version="1.0"?> <connectionStrings> <add name="connectionName" connectionString="[connection string goes here]"/> </connectionStrings>
Like that we have created an “incapsulation” of the information, and can easily deal with issues like source control, deployment and such of that information.
Whilst there are certainly plenty of solutions, none of them really give you a huge amount of control over the generated configuration, one solution that I noted in my edit where you get a huge amount of control but with the overhead of having to write an xslt file, was using an xslt build task to use the template web.config/app.config from source control (which I personally name web.base.config/app.base.config), and use an xslt file to transform the version controlled config file at build time, and generate a web.config/app.config.
Here is an example of an xslt build task (although you may want to write it to your own coding standards), and an example of a mundane xslt transform that will change the value of a connection string and copy everything else in the config:
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"> <xsl:output method="xml" indent="yes"/> <!-- Copy all. --> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <!-- Swap connection string. --> <xsl:template match="/configuration/connectionStrings/add[@name='my_connection_string_name']"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> <xsl:attribute name="connectionString">my replacement connection string value</xsl:attribute> </xsl:copy> </xsl:template> </xsl:stylesheet>
This is a mediocre example, but you can imagine you can completely transform entire sections where you previously would struggle with an inheritance based scenario.
The configuration of an application can be split into two categories.
- Application specific
- Deployment specific
Application specific configuration includes things like caching implementation, business rules implementation, and will apply to every deployment of the application. This should go into the web.config file that is part of the application directory structure and is checked into source control.
Deployment specific configuration includes things like connection strings, timeout periods, etc, and may differ from one deployment to another. This should be entered as part of the configuration of the IIS instance that is involved in the deployment and preserved by whatever backup strategy is in place for the machine in question.
As far as I can tell, this is exactly what the hierarchical nature of the web.config files was designed to handle.
The advantages of such an arrangement are…
- No need to worry about which developer’s version of the settings end up in source control, because none of them do.
- Every deployment uses the same binary, so deployment issues are more likely to involve the deployment configuration.
- Subsequent deployments should need no deployment specific configuration changes, because they are already in place.
We don’t store environment settings in the web.config.
They’re stored in a database.
This enables us to do xcopy deploys, and to store the web.config file in our version control system.
Access to the database is via one registry key.
What you’re describing sounds a lot like using a Machine.config file to store connection strings. I haven’t seen this mentioned yet, so have you tried it? It looks like you can use a global Web.config that sits beside your Machine.config as well.
A few links:
ASP.NET Configuration File Hierarchy and Inheritance
Difference between Web.config and Machine.config