January 2010

Volume 25 Number 01

Extreme ASP.NET - Text Template Transformation Toolkit and ASP.NET MVC

By K. Scott Allen | January 2010

Microsoft Visual Studio includes a code generation engine known as T4 (which is short for Text Template Transformation Toolkit). You’ve probably already used T4 templates in Visual Studio without even knowing they were working behind the scenes. In this article I’m going to give you a basic introduction to T4 templates and show you how ASP.NET MVC uses this technology. I’ll also show you how to customize T4 templates to enhance your day-to-day work with the MVC framework.

The basic idea behind the template toolkit is to parse an input file and transform it into an output file. The input file is a template—a text file with a .tt file extension. The output file will also contain text, and the text can be C# code, Visual Basic code, Web Forms code, markup or anything else you need to generate.

The easiest way to see T4 in action is to create a new project in Visual Studio. I’ll be generating C# code in this article, so you can use any project type that compiles C# code. Once the project is opened, right-click the project and select Add | New Item. Select Text File from the Add New Item dialog (there’s no item template dedicated to T4 in Visual Studio 2008, but there will be in 2010), and name the file Simple.tt (make sure you use the .tt extension). Once the file is loaded into the project you’ll immediately see a Simple.cs file appear behind Simple.tt in the Solution Explorer window (see Figure 1).

Figure 1 C# File Behind a T4 Template

image: C# File Behind a T4 Template

Both Simple.tt and Simple.cs will start as empty files. If you right-click the Simple.tt file and select Properties, you’ll see that Visual Studio assigned TextTemplatingFileGenerator as the custom tool for the file (see Figure 2). This generator is the T4 engine that will transform the template file into a file full of C# code.

Figure 2 Properties of the T4 Template

image: Properties of the T4 Template

To make the template do something interesting, add the following code:

<#@ template language="c#v3.5" #>
<#@ assembly name="System.Web.Mvc.DLL" #>
<#@ import namespace="System.Web.Mvc" #>

public class Test
{
<# for(int i = 0; i < 5; i++) { #> 
  public int Prop<#= i #> { get; set; }
<# } #>
}

The code begins with some directives. Directives allow you to specify the programming language for the template and include namespaces and assemblies required by the code in the template. I want to stress that I’m talking about settings required to execute code in the template and not code in the project itself. You can also use a directive to specify the extension of the output file. The default is C#, but as I mentioned earlier, you can generate Visual Basic code, XML, HTML or any other textual artifact.

The directives I’m using tell the template engine to use the C# compiler that comes with the Microsoft .NET Framework 3.5. It also tells the template engine to reference the ASP.NET MVC assembly and to bring the System.Web.Mvc namespace into scope. The MVC assembly and namespace are not actually required by the simple code in the template, but I put them in the template as an example.

After the directives, the text you see that’s not between <# and #> delimiters is put verbatim into the output file. The text between <# and #> is C# code. The template engine will parse the code and add it to a class for execution (a class ultimately derived from the TextTransformation class in the Microsoft.VisualStudio.TextTemplating assembly). This process is similar to the ASP.NET view engine process where the code and markup in an .aspx file are added to a class ultimately derived from System.Web.UI.Page. If you’ve already been writing your MVC views using the Web Forms view engine, you’ll feel comfortable creating templates. In .aspx files you can use C# code to generate HTML. In my .tt file, I’m using C# code to generate C# code.

The code I have in Simple.tt will produce the following C# output in Simple.tt.cs:

public class Test
{
  public int Prop0 { get; set; }
  public int Prop1 { get; set; }
  public int Prop2 { get; set; }
  public int Prop3 { get; set; }
  public int Prop4 { get; set; }
}

Of course, the Test class is completely useless and wholly uninteresting, but I hope it gives you some idea of the possibilities that exist with T4 templates. Because you’re writing C# code in the template, you can connect to databases, read data from the file system, parse XML or use any .NET class to connect and read metadata that exists somewhere in your environment. This metadata, like a database schema or the types inside another assembly, is information you can use to generate classes. The classes will become part of the current project, so they will compile into the current assembly and you can use them in your application.

T4 Editing

When you’re editing T4 templates in Visual Studio, you’ll have no help from the language services in the IDE, like IntelliSense and syntax highlighting. There are two solutions to this problem. One is the Visual T4 editor available from Clarius Consulting (http://visualstudiogallery.msdn.microsoft.com/40a887aa-f3be-40ec-a85d-37044b239591). Another solution is the Tangible T4 Editor from Tangible Engineering (t4-editor.tangible-engineering.com).

With a basic understanding of how T4 templates work, let’s look at how the MVC framework uses T4 templates.

T4 in ASP.NET MVC

You’ve been using T4 templates every time you used the Add View or Add Controller features in an ASP.NET MVC project. These templates are located in your Visual Studio installation within the Common7\IDE\ItemTemplates\CSharp\Web\MVC 2\CodeTemplates folder. Visual Basic versions of the template also exist, but I’ll leave it as an exercise for the reader to deduce the folder name.

The templates themselves provide a great education on the value and features of T4. For example, here is an excerpt from List.tt in the AddView subfolder of CodeTemplates:

if(!String.IsNullOrEmpty(mvcViewDataTypeGenericString)) {
  Dictionary<string, string> properties = 
    new Dictionary<string, string>();
  FilterProperties(mvcHost.ViewDataType, properties);
#>