One of the big pains that I've run into creating a build process for a web site is the web.config. When running in development, the web.config needs a certain set of development-only settings that get changed for production. For example connection strings. When developing, the web.config points to the development database but in production, it should point to the production database.
In the past I've kept two configuration files. Web.config and Release.config. At build time, the web.config was overwritten with a copy of the release.config. Horrible you say? Yeah, I know. For those that it's not obvious to, the release.config and web.config will contain a lot of duplicate information. Especially if you extend the web.config with your own custom configuration sections. Let the synchronization issues ensue!
The ideal solution to handling the web.config is simply to change those values that you want changed. But how to do this without writing some kind of script to find and replace these values?
Thankfully, the configuration file is just XML. XML can be easily modified using XSLT. And guess what! NAnt (our build script language of choice) has a <style> step that allows you to perform an XML transformation with XSLT. Ok, the only thing I needed now was time to get back up to speed on XSLT. As you may have guessed it, I'm writing this post because I found that time. Below is the code needed to make those changes.
XSLT:
<?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 every node from the web.config applying templates when possible-->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<!--Remove custom debugging app settings-->
<xsl:template match="/configuration/appSettings/add[@key='CreditCardTestMode']" />
<!--Remove Conditional Compilation Symbols - Removes the 'compilerOptions' attribute-->
<!--If you use the DEBUG conditional compilation symbol, you will have to transform your web.config before compiling your website.-->
<xsl:template match="/configuration/system.codedom/compilers/compiler/@compilerOptions" />
<!--Remove Debug Trust-->
<xsl:template match="/configuration/system.web/compilation/@debug">
<xsl:attribute name="debug">false</xsl:attribute>
</xsl:template>
<!--Switch to production database-->
<xsl:template match="/configuration/connectionStrings/add[@name='myDB']/@connectionString">
<xsl:attribute name="connectionString">Data Source=SERVER; Initial Catalog=MYDB; User ID=DBO; Password=REALLYSTRONGPASSWORD;Application Name=APPLICATION;</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
NAnt Step:
<!--Build website using the aspnet compiler-->
...
<!--Modify web.config for production-->
<style style="${buildfiles.path}webconfig.xslt" in="web.config" out="${website.output.path}web.config" />One of the other big hurdles is the DEBUG conditional compilation symbol. Most of our web projects depend on that symbol so things happen a little different while in development (such as exception handling). Because of this, our web.config would have to be transformed before we compiled. Thankfully, that code should be able to be removed from the web project and moved into the supporting project. Yay! Less code in the web project! I'm all for less code in the web project. That's the way it should be.