There are many steps one need to do to setup a good working development environment. In large products where there are many project files and solutions that needed to be build in a certain order, managing all the config files can be a nightmare. This post is not going to tell you how to do things in such a large scale, but I want to show how easy is to use NAnt tool to do web config transformations. This will become one of the steps that we need to do as part of a continuous integration (CI) build or a local build. I have seen development teams struggle with setting up local development environment. This becomes a pain when project builds are not well thought, or designed well. My advise to any development team or developer is to spend some time to think thru our development process and build and deployment process. Treat this as a technical debt and deal with it aggressively before it reaches a point where you are spending hours every day trying to build your solution(s) so that you can write code.
Enough of the story, let us get to the point.
Our aim is to transform a template config file. Let us name config files in the format web.config.TEMPLATE. Idea is to use NAnt to do a transformation while copying this file to the target name of web.config. In the template file, you will need to tokenize the parts that you want to change depending on the environment. For example, when you are developing local, you may want to point to your local database server, in a QA environment, this will be a QA database server. You got the idea.
NAnt works with a project file for the build. There are several tasks NAnt can do, one of these tasks is a copy task. All NAnt related files are XML files. You can run NAnt from the command prompt and it takes many command line parameters.
nant.exe -buildfile:config.build -D:sourcefile=.\source\web.config.TEMPLATE -D:propertyfile=.\build\local.properties -D:destinationfile=.\source\web.config
Command line switch -buildfile is the name of the build file; -D allows us to pass multiple property name-values.
For our little experiment, I want to build web.config files for my two scenarios, one is when I work on local machine, I need a local version of web.config created and when I move to my QA environment, I need a different web.config file. The following picture shows how files and folders are setup:
What I have in \build folder – property files for various environments
what I have in \source folder – we.config.TEMPLATE file (actual config file is generated here itself)
This is the NAnt project file. A default.properties is loaded always. We will use this file to capture all the properties that are common across the different configurations
we are building.
<project default="buildconfig">
<property name="propertyfile" value="invalid.file" overwrite="false" />
<if test="${file::exists('default.properties')}">
<echo message="Loading default.properties" />
<include buildfile="default.properties" />
</if>
<echo message="Loading ${propertyfile}" />
<include buildfile="${propertyfile}" failonerror="false" unless="${string::contains(propertyfile, 'invalid.file')}" />
<target name="buildconfig">
<copy file="${sourcefile}" tofile="${destinationfile}" overwrite="true">
<filterchain>
<expandproperties />
</filterchain>
</copy>
</target>
</project>
So for example we have the following we.config.TEMPLATE file that needs to get build for local and QA environments,
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add name="DatabaseConnection" connectionString="Server=${DBServerName};Database=${DBName};Trusted_Connection=${TrustedConnectionValue}" />
</connectionStrings>
</configuration>
So we have tokens for database server, database name and trusted connection value. For example, if our database name and the trusted connection value is not changing from environment to environment, then you keep these property values in default.properties file. Since this file is loaded always (see build file), NAnt will be able to replace those tokens. Furthermore we will pass the environment specific property file along with the command line that is used to run NAnt.
Our default.properties file:
<project> <property name="DBName" value="FancyApp" /> <property name="TrustedConnectionValue" value="true" /> </project>
and our local.properties file; where we specify the database server name as (local). When we are running for another environment like QA, a qa.properties file can be created and passed in as parameter.
<project> <property name="DBServerName" value="(local)" /> </project>
So, now with these files all set in the right places, if we run the commandline for NAnt, NAnt will run the
I am planning to expand this post in coming weeks, to show how we can use MSBuild to build the project,, deploy it to the specified location, how we can automatically checkout files from SVN, run some Unit/INtegration tests etc.
Once we have a full local build worked out, I will expand it further to use a CI Build server like Team City to kick off automated builds.
Exciting…
Until then, be productive

