Anatomy of the T4 Text Template

Visual Studio 2010 uses T4 text templates for code generation and within this blog post we’ll examine the anatomy of a text template and see how easily code and other text can be generated.

Let’s take a look at an example in Visual Studio, we’ll create a new Visual C# empty project and add two new text templates files, one named AdventureWorks.tt and the other named SqlServerSmo.tt. You can find text templates within the Add New Item dialog by searching for “text template” within the search control. We’ll use the Text Template rather than Preprocessed Text Template within this example.

Open the file properties for the SqlServerSmo.tt template and delete the value from the Custom Tool option, then ensure that the value of the Custom Tool option for the AdventureWorks.tt template is TextTemplatingFileGenerator.

When writing the text templates we compose the templates using directives, text blocks, and control blocks.

Directives allow instructions to be passed to the text templating engine and there are six standard directives, although you also can create your own custom text template directive processors too!

We’ll begin by replacing the text within the SqlServerSmo.tt template with the template directive shown below.

<#@ template debug="true" hostspecific="true" language="C#" #>

In the above example we’re setting debug=”true”, which will allow us to use the Visual Studio debugger to step through the template. We’re also setting hostspecific=”true”, which allows us to specify that the template is dependent upon features within a particular host, such as Visual Studio.

Given that text templates can use programming language constructs within control blocks, it is necessary to specify the language to be used by the templating engine. At the time of writing the only two supported languages are C# and VB.

We’ll then add the following assembly directives, adding references to the assemblies we’ll be using from the SQL Server SMO framework. SQL Server SMO is a management framework that is available for download as part of the SQL Server 2008 R2 Feature Pack.

<#@ assembly name="Microsoft.SqlServer.Smo" #>
<#@ assembly name="Microsoft.SqlServer.ConnectionInfo" #>
<#@ assembly name="Microsoft.SqlServer.Management.Sdk.Sfc" #>

With the required assemblies referenced in our template we now need to use the import directive, specifying the required namespaces containing the types we’ll be using within the template. The import directive is essentially the same as the C# using directive or VB Imports statement.

<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="Microsoft.SqlServer.Management.Smo" #>

Using the SQL Server SMO framework we’ll create a class feature block, denoted by the <#+ … #> section, within which we’ll define a property to retrieve the list of table names from the sample AdventureWorks database.

<#+
private List<string> Tables
{
get
{
Server server = new Server("localhost");

        List<string> tables = new List<string>(); 

        foreach(Table table in server.Databases["AdventureWorks"].Tables)
{
tables.Add(table.Name);

        return tables;
}
set
{
throw new NotSupportedException();
}
}
#>

We’ll now move to the AdventureWorks.tt template, replacing the text within the template with the include directive shown below which allows us to reference the SqlServerSmo.tt template we previously created. Given that we’re generating classes defined within the C# programming language we’ll also use the output directive to specify that the generated file will use the “.cs” file extension.

<#@ include file="SqlServerSmo.tt"#>
<#@ output extension=".cs" #>

 

AdventureWorks.tt will then define the source file header comments with a simple text block that will be written verbatim to the AdventureWorks.cs file that will be created by the text templating engine.

//-----------------------------------------------------------------------
// <copyright file="AdventureWorks.cs" company="Microsoft">
// Copyright (c) Doug Holland, Microsoft. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

We’ll then use the Tables property defined within the SqlServerSmo.tt template to create partial class declarations for each table defined within the sample AdventureWorks database. As with the file header comments, the namespace declaration is written verbatim although control blocks are used, denoted by the <# … #> sections, to specify a foreach loop to iterate through the names of tables and then to name the partial class with the name of the associated table.

namespace AdventureWorks
{
<#
foreach (string name in Tables)
{
#>
public partial class <#=name#>
{
}

<#}#>
}

 

You can hopefully see here the anatomy of the T4 text template and how its power and flexibility comes from the ability to embed program code within the template to control the text generated. Using the SQL Server SMO framework it would then be possible to determine the columns defined within each table and create properties, within the generated classes, representing each column.

If you have any form of metadata upon which you would like to generate code, or any other text for that matter, then I believe that T4 provides a very compelling code generation solution.