Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WinForms

Personalize .NET Configuration Files with NANT

5.00/5 (2 votes)
20 Sep 2010CPOL7 min read 53.3K   225  
Brings you the ability to personalize your configuration files per developer, per machine, per configuration...

Introduction

.NET's configuration files (such as app.config, web.config, etc.) are convenient and easy to use, but are statics and a real pain to manage in a collaborative environment using versioning tools like SVN, TFS, etc.

Although Microsoft introduced web.config transforms in Visual Studio 2010, it suffers (stop me if I'm wrong) from several limitations:

  • It only works for web.config (a workaround exists for app.config)
  • It don't allow per developer web.config
  • You must be confident with XSLT like technologies
  • It only works with Visual Studio 2010 (obviously)

If you want to personalize your configuration files, not depending of the project type (WinForm, ASP.NET, Console, etc.), not depending of your version of Visual Studio, this article brings you a free, easy to use, and customizable solution that will fit your need.

Background

The idea of personalized configuration files came from my experience as team leader, wasting a part of my time and energy to maintain configuration files and solve versioning's conflicts of a dozen of .NET developers under SVN.

The fact is that each developer will alter checkouted (SVN terminology) configuration files with its own values (connection strings, debug mode, and so on...) to fit his/her need and will commit its personal changes, making other developers lose their values or have conflicts on the next update (XML are badly merged with SVN).

"Ready to go" Sample Project

The sample project provided with this article shows you how to personalize a value in a configuration file called "App.Config" in respect of Visual Studio's configuration (Debug or Release).

Note: NANT is configured to run from "%ProgramFiles%\Nant\bin\NAnt.exe".

At each compilation, NANT will run tasks in "Default.build" (blue circle) at pre built, getting properties in "VisualStudioConfiguration" folder and copying templated "App.Config" to the project's root "green arrow).

SolutionExplorerArrows.gif

Step by Step Personalization

Download and Install / Deploy NANT

NANT is a great open source .NET build tool (port of the Java ANT project) allowing you to write build file in XML format. All of this article is based on it because it allows us to copy files and replace embedded properties (symbols) with contextual values.

First, you need to get and deploy the latest stable version of NANT on each computer of your teamate, targeting the .NET framework of your choice (from 1.0 up to 4.0).

Decompress the archive in the folder of your choice.

Notes

  • In a collaborative environment, it's very important that everyone install NANT in the same directory, for example "%ProgramFiles%\Nant", in order to have a known executable path like "%ProgramFiles%\Nant\bin\NAnt.exe".
  • NANT is a 32 bit executable so beware of 64 bit systems if you install it in "%ProgramFiles%" folder, you'll need to install it in "Program Files (x86)", not "Program Files".
  • This article will not explain how to make build files, but how to use NANT to personalize configuration files.

Prepare a Configuration File to be Personalized

Choose a project and a configuration file you want to personalize. Then:

  1. Create a folder to put your NANT stuff, let say its name is "YourNantDirectory".
  2. Create a subfolder to put your templated configuration files, let's say its name is "YourTemplatesDirectory" (path "YourNantDirectory\YourTemplatedFilesDirectory").
  3. If needed, create another subfolder where your final configuration files will be stored, let's say its name is "YourCopiedFilesDirectory" (path "YourNantDirectory\YourCopiedFilesDirectory"). You don't have to create it if you just want to personalize root configuration files such as Web.config or App.config.
  4. Move your configuration file(s) in this folder.
  5. Don't forget to commit the move and ignore the original file (SVN terminology).

Create the Build File

The NANT build file is the heart of the process, it contains properties (symbols), tasks, etc. in XML format. To create it:

  1. Explore your solution
  2. Create your build file with the template bellow
  3. Replace "YourProjectName" with the friendly name of your project (this can be very useful for other use of NANT described at the end of this article)
  4. Replace "YourTemplatedFilesDirectory" with the right directory name and "YouConfigurationFile" with the name of the templated configuration file (for example App.config, Web.Config, etc.)
  5. Choose the right encoding for the input file and the output file (read NANT documentation for more attributes)
  6. Don't forget to add the "expandproperties" filter chain to get your properties expanded

Note

  • The "copy" NANT task is a commonly used one, whose goal is to copy an input file to an output file
  • Beware of paths, they are relative in respect of this build file!

Your build file should now look like:

XML
<?xml version="1.0"?>
<project default="YourProjectName">
    <target name="YourTargetName">
        <copy file="YourTemplatedFilesDirectory/YouConfigurationFile" 
		tofile="../YouConfigurationFile" inputencoding="utf-8" 
		outputencoding="utf-8" overwrite="true">
            <filterchain>
                <expandproperties />
            </filterchain>
        </copy>
    </target>
</project>

Launch NANT Before Each Build

NANT has to be triggered before each build to generate configuration files, to do so:

  1. Right click on your future NANT enabled project and choose "Properties"
  2. Click "Generation events" tab
  3. Add the following line to invoke NANT before each build (pre-build)
  4. Don't forget to replace "YourTargetName" with the name of the target in the build file
  5. Replace "YourRelativeDirectoryToBuildFile\YourBuildFile" with the relative path to your future build file, in respect of the root of your project:
"%ProgramFiles%\Nant\bin\NAnt.exe" YourTargetName 
/f:"$(ProjectDir)YourRelativeDirectoryToBuildFile\YourBuildFile"
    exit 0

You're now ready to make your first compilation test, build your project and look at the console output, you must have something like this:

"%ProgramFiles%\Nant\bin\NAnt.exe" PreBuild 
	/f:"YourProjectAbsolutePath\YourRelativeDirectoryToBuildFile\YourBuildFile"
exit 0
NAnt 0.85 (Build 0.85.2478.0; release; 14/10/2006)
Copyright (C) 2001-2006 Gerry Shaw
http://nant.sourceforge.net
 
Buildfile: file:///YourProjectAbsolutePath/YourRelativeDirectoryToBuildFile/YourBuildFile
Target framework: Microsoft .NET Framework 2.0
Target(s) specified: PreBuild 
 
  [include] YourProjectAbsolutePath\YourRelativeDirectoryToBuildFile\YourBuildFile(?,?):
 
YourTaskName:
 
     [copy] Copying 1 file to 'YourProjectAbsolutePath\YourConfigurationFile'.
 
BUILD SUCCEEDED - 0 non-fatal error(s), 0 warning(s)

If this build didn't succeed, check your build file.

Personalize Your Configuration File

Let's say you want to personalize your Web.config or App.config file, the best example is the connection string.

Open the templated configuration file and replace the current connection string with a NANT property such as "AppSettings.ConnectionString":

XML
<configuration>
    <appSettings>
        <add key="ConnectionString" value="${AppSettings.ConnectionString}" />
    </appSettings>
</configuration>

Note: Never modify the generated configuration file, else you'll lose your modifications at the next build (it's a common mistake that everyone is doing a day or other).

If you try to compile your project again, you'll have the following error and the output file will be empty:

Cannot copy 'YourProjectAbsolutePath\YourTemplatedFilesDirectory\YourConfigurationFile' 
	to 'YourProjectAbsolutePath\YourConfigurationFile'.
    YourProjectAbsolutePath\YourRelativeDirectoryToBuildFile\YourBuildFile(?,?):
    Property evaluation failed.
    Expression:   <configuration>      <appsettings>          
	<add key="ConnectionString" value="${AppSettings.ConnectionString}">      
	</add>  </appsettings>      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        Property 'AppSettings.ConnectionString' has not been set.

The final goal of this article is to get personalized configuration files, but if you want, or if you need, you can define a default value for this property in the build file, by adding this node to under the project node:

XML
<property name="AppSettings.ConnectionString" overwrite="false" 
	value="Your default connection string"></property>

Per Windows User Configuration File

It's time to get into the heart of the matter: get personalized configuration file per Windows user.

  1. Open your project "YourNantDirectory" NANT folder
  2. Create a subfolder to put Windows user's properties files, let's say its name is "WindowsUsersProperties" (path is "YourNantDirectory\YourTemplatedFilesDirectory")
  3. Choose (or not) a file extension for the properties file, "properties" for example

First, we define a property in the build file, to keep in mind the environment's username:

XML
<property name="Username" value="${environment::get-user-name()}" 
	overwrite="false" />

Then we include the property file of the current Windows user:

XML
<include buildfile="YourNantDirectory/WindowsUsersProperties/${Username}.properties" 
	failonerror="false" if="${Username != ''}" />

No you can create your own property (yourWindowsUsername.properties) file to personalize the connection string:

XML
<project>
    <property name="AppSettings.ConnectionString" value="MyConnectionString" />
</project>

Build your project to see your connection string in the final configuration file!

Per Machine User Configuration File

Per machine (computer) configuration files is also possible (but quite useless in respect of per Windows user configuration file).

The process is quite the same. You must define a property in the build file, to keep in mind the environment's machine name:

XML
<property name="MachineName" value="${environment::get-machine-name()}" 
	overwrite="false" />

Then we include the property file of the current machine :

XML
<include buildfile="YourNantDirectory/MachinesProperties/${MachineName}.properties" 
	failonerror="false" if="${MachineName != ''}" />

Per Configuration User Configuration File

This is the closest type of personalization in respect of Visual Studio 2010 web.config transforms feature.

Since we cannot access the current Visual Studio's configuration in a NANT built file, the tweak is to get it in from the command line (see "Launch NANT before each build" section) in the following manner:

"%ProgramFiles%\Nant\bin\NAnt.exe" YourTargetName 
	/f:"$(ProjectDir)YourRelativeDirectoryToBuildFile\YourBuildFile" 
	-D:Configuration="$(ConfigurationName)"
    exit 0

Now we can include the property file of the current Visual Studio's configuration with:

XML
<include buildfile="YourNantDirectory/VisualStudioConfigurationsProperties/
	${Configuration}.properties" failonerror="false" if="${Username != ''}" />

Then we can (for example) automatically change the debug attribute's value of the Web.config, with a property such as:

XML
...
<compilation debug="${AppSettings.Compilation.Debug}">
...

With the following Debug.properties file:

XML
<project>
    <property name="AppSettings.Compilation.Debug" value="true" />
</project>

And this Release.properties file:

XML
<project>
    <property name="AppSettings.Compilation.Debug" value="false" />
</project>

That's all folks.

Other Ideas

If you ever used SQL Server Profiler with a SQL Server instance used by your team, you probably have some problems to see only your SQL queries. You can use NANT to automatically append your Windows userme to your SQL Server's connection string, in order to filter on it.

If you have a big JavaScript file, you can split it into small files, then aggregate and even compress it.

Your limit will be your imagination or simply your need, just post your ideas in this article comments...

Points of Interest

This article did not require advanced skills, but it's a good idea (in my sense) that I'm pleased to share with you and that will probably make your daily work easier, as it has made mine since 2008.

NANT is a great tool that brings you the opportunity to automatize a lot of boring tasks. If your imagination is stopped by its builtin tasks, you can search for custom tasks over the Internet (JavaScript compression, etc.).

History

  • 2010/09/13: First version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)