How to use T4 to generate .config files


This article demonstrates how to create and use a simple T4 template to generate App.config files for development, testing and production environments in Visual Studio.

Overview

When developing an internal enterprise application, you typically have several deployment environments - development, testing, staging and production. Each environment consists of one or more servers where the application is deployed. Application is configured differently in each environment. For example, in development environment application connects to development database server and in production it connects to the production database server. In a .NET application, you typically accomplish this by storing configuration settings in application configuration file. The application is then deployed to each environment with a configuration file modified to be specific to that environment.

There are several different ways of producing configuration files specific to each deployment environment. You can create and maintain 4 separate copies of the file manually (this becomes problematic as the size of configuration file increases); you can use MSBuild to create copies of the original file during build and then use Regex or ModifyFile from SDC Tasks to replace original settings with environment-specific ones; you can write custom code to do this, etc. As the example below illustrates, you can also generate the files using simple T4 templates.

Example

In order to follow the walkthrough, you will need Visual Studio 2005 Standard (or higher) Edition and DSL Tools installed on your computer. You may also want to install T4 Editor by Tangible Engineering, which adds IntelliSense and syntax highlighting to Visual Studio text editor for T4 templates.

1. In Visual Studio, create a new C# Console Application project.

2. Add a connection string to the application settings. You will have app.config file similar to this:

<?xml version=1.0encoding=utf-8?>
<configuration>
  <connectionStrings>
    <add name=ConsoleApplication1.Properties.Settings.NorthwindconnectionString=Data Source=.;Initial Catalog=Northwind;Integrated Security=TrueproviderName=System.Data.SqlClient/>
  </connectionStrings>
</configuration>

You will notice that I have a connection to the Northwind database on my local machine.

3. Add a new text file called App.tt to the project. Copy the text from App.config, paste it to App.tt and modify it like so:

<#@ template language=C##>
<#@ output extension= .config#>
<?xml version=”1.0″ encoding=”utf-8″ ?>
<configuration>
  <connectionStrings>
    <add name=”ConsoleApplication1.Properties.Settings.Northwind”
      connectionString=”Data Source=.;Initial Catalog=Northwind;Integrated Security=True”
      providerName=”System.Data.SqlClient” />
  </connectionStrings>
</configuration> 

When you save App.tt, you will notice that App.config is now located under App.tt in Solution Explorer. Visual Studio recognized .tt extension and used App.tt to generate App.config. App.config itself has not changed because its entire text is now in App.tt.

4. Modify App.tt to make connection string a parameter of the template. App.tt should look like so:

<#@ template language=C##>
<#@ output extension= .config#>
<?xml version=”1.0″ encoding=”utf-8″ ?>
<configuration>
  <connectionStrings>
    <add name=”ConsoleApplication1.Properties.Settings.Northwind”
      connectionString=”<#= this.NorthwindConnectionString #>”
      providerName=”System.Data.SqlClient” />
  </connectionStrings>
</configuration>
<#+
  string NorthwindConnectionString = “Data Source=.;Initial Catalog=Northwind;Integrated Security=True”;
#>

In this version of App.tt, NorthwindConnectionString is a private field of the template. We initialize the field in-place and use it in the template to supply value for connectionString attribute.

5. Add a new text file called Dev.tt to the project and enter the following text in it:

<#
  NorthwindConnectionString = “Data Source=DEV-SERVER;Initial Catalog=Northwind;Integrated Security=True”;
#>
<#@ include file=App.tt#>

This template includes the App.tt template we created earlier and overrides NorthwindConnectionString value with a connection string that points to Northwind database on our development server. When you save Dev.tt, Visual Studio will automatically generate Dev.config and add it to your project under Dev.tt. Contents of Dev.config will look like so:

<? xml version=”1.0″ encoding=”utf-8″ ?>
<configuration>
  <connectionStrings>
    <add name=ConsoleApplication1.Properties.Settings.NorthwindconnectionString=Data Source=DEV-SERVER;Initial Catalog=Northwind;Integrated Security=TrueproviderName=System.Data.SqlClient/>
  </connectionStrings>
</configuration>

Notice that it looks exactly like App.config but connectionString attribute points to DEV-SERVER instead of local server.

6. In Solution Explorer, set “Copy to Output Directory” property of Dev.config to “Copy if newer”.

This will make Visual Studio copy Dev.config to the build output directory (such as bin\Debug).

7. Modify your deployment script to copy Dev.config to the development environment instead of application .config.

Your script will also need to rename Dev.config after copying it to the target server to match the name of your assembly (ConsoleApplication1.exe.config in this example).

8. Repeat steps 5-7 to create .config files for each deployment environment (Test, Staging, Production).

Adding new settings to the template

When you need to add a new setting to the config file, you need to make sure that all templates are updated accordingly. For example, let’s suppose that you opened project properties, selected Settings tab and add added a new connection string for Pubs database. Settings editor modified App.config directly and it now looks like this:

<? xml version=”1.0″ encoding=”utf-8″ ?>
<configuration>
  <connectionStrings>
    <add name=ConsoleApplication1.Properties.Settings.NorthwindconnectionString=Data Source=.;Initial Catalog=Northwind;Integrated Security=TrueproviderName=System.Data.SqlClient/>
    <add name=ConsoleApplication1.Properties.Settings.PubsconnectionString=Data Source=.;Initial Catalog=Pubs;Integrated Security=TrueproviderName=System.Data.SqlClient/>
  </connectionStrings>
</configuration>

However, App.tt has not changed and still looks like it did in step 4. Pubs connection string will not appear in Dev.config and will be removed from App.config if we regenerate it from App.tt.

9. Copy Pubs connection string from App.config to App.tt and modify it like so:

<#@ template language=C##>
<#@ output extension= .config#>
<?xml version=”1.0″ encoding=”utf-8″ ?>
<configuration>
  <connectionStrings>
    <add name=”ConsoleApplication1.Properties.Settings.Northwind”
      connectionString=”<#= this.NorthwindConnectionString #>”
      providerName=”System.Data.SqlClient” />
    <add name=”ConsoleApplication1.Properties.Settings.Northwind”
      connectionString=”<#= this.PubsConnectionString #>”
      providerName=”System.Data.SqlClient” />
  </connectionStrings>
</configuration>
<#+
  string NorthwindConnectionString = “Data Source=.;Initial Catalog=Northwind;Integrated Security=True”;
  string PubsConnectionString = “Data Source=.;Initial Catalog=Pubs;Integrated Security=True”;
#>

10. Override PubsConnectionString value in Dev.tt like so:

<#
    NorthwindConnectionString = “Data Source=DEV-SERVER;Initial Catalog=Northwind;Integrated Security=True”;
    PubsConnectionString = “Data Source=DEV-SERVER;Initial Catalog=Pubs;Integrated Security=True”;
#>
<#@ include file=App.tt#>

When you save Dev.tt, Visual Studio will regenerate Dev.config which will now have both Northwind and Pubs connection strings and will look like this:

<?xml version=1.0encoding=utf-8?>
<configuration>
  <connectionStrings>
    <add name=ConsoleApplication1.Properties.Settings.NorthwindconnectionString=Data Source=DEV-SERVER;Initial Catalog=Northwind;Integrated Security=TrueproviderName=System.Data.SqlClient/>
    <add name=ConsoleApplication1.Properties.Settings.NorthwindconnectionString=Data Source=DEV-SERVER;Initial Catalog=Pubs;Integrated Security=TrueproviderName=System.Data.SqlClient/>
  </connectionStrings>
</configuration>

11. Repeat steps 9-10 for each new setting you need to add to App.config.

Conclusion

T4 engine allows you to generate multiple application .config files from a single template. It encourages (but not requires) including environment-specific configuration files in the Visual Studio project and placing them in source control with the rest of the source code. For each additional .config file, it requires separate template that includes original App.tt and provides values for template parameters. When using tools that manipulate App.config (such as settings editor in Visual Studio) you need to be careful to move the additional settings generated by the tool into App.tt to avoid loosing them and make them appear in all generated .config files.

About T4

T4 (Text Template Transformation Toolkit) is a template-based code generation engine. It is available in Visual Studio 2008 and as a download in DSL and GAT toolkits for Visual Studio 2005. T4 engine allows you to use ASP.NET-like template syntax to generate C#, T-SQL, XML or any other text files.

For more information about T4, check out my previous article.

Download

T4 templates and source code used in this article are available for download here.


Write a Comment

Take a moment to comment and tell us what you think. Some basic HTML is allowed for formatting.

Reader Comments

Thank you for this, was banging my head against a brick wall in terms of deploying Windows services, every thing with them just doesn’t fit. NowI have a template for each build config and the option to deploy and presto. it just works ! thanks again.

[…] can be generated from a master template to reflect different connection strings, etc. Oleg Sych has a nice write-up on this. Hint: hand-edit your .csproj file and use the DependentUpon element to keep your project view […]