Extreme ASP.NET
Text Template Transformation Toolkit and ASP.NET MVC
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
.png)
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
.png)
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.
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);
#>
<table>
<tr>
<th></th>
<#
foreach(KeyValuePair<string, string> property in properties) {
#>
<th>
<#= property.Key #>
</th>
<#
}
#>
The job of List.tt is to produce an .aspx file that will display a collection of model objects in tabular form. In the template you can see the table, tr and th tags being written. To produce the .aspx file the template needs some contextual information, like the name of the master page it should use and the type of the model. The template can retrieve this information from its host object. The host object sits between a template and the T4 engine and can give a template access to resources (like local files) and environmental settings. Typically, the host is Visual Studio, but the MVC team created a custom host of type MvcTextTemplateHost in the Microsoft.VisualStudio.Web.Extensions assembly. It’s this custom host object that carries forward information you enter in the Add View and Add Controller dialog boxes, which are the closest things you’ll find to wizards in an MVC project.
List.tt will loop through the displayable properties of the strongly typed model object and create a table with a column for each property. The template uses reflection to discover the model’s available properties in a FilterProperties method. FilterProperties is a helper method defined later in the template file. The template also sets up links to navigate to the edit and details actions, and sets up the proper @ Page or @ Control directives for the .aspx, depending on whether you’re creating a view or a partial view.
When the template is finished running, you’ll have a new .aspx view with everything you need to display a collection of model objects. Chances are you’ll go into the .aspx file and perform some fine-tuning to make the view consistent with the look and feel of the views in the rest of your application.
If you find you’re always making the same changes to these generated views (or to the controller code generated by Controller.tt), you can save time by modifying the templates themselves. For example, you could modify the built-in templates to add class attributes for style rules you use in your project, or perhaps something even more drastic. Keep in mind that modifying the template files in the Visual Studio installation directory will change the code generated in all the projects you work with on your machine. If you want to change the generated code for a single project, you can do this, too.
Per-Project T4 Customization
If you want custom versions of the code-generation templates on a per project basis, your first step is to copy the CodeTemplates folder from the Visual Studio installation and paste it into the root of your ASP.NET MVC project. You don’t need to copy all the templates into your project, however. You can copy only the templates you want to modify. There are a total of six MVC code-generation templates, one for adding a controller (Controller.tt) and five for adding views (Create.tt, Details.tt, Edit.tt, Empty.tt, List.tt). If a template exists in your project, it will override the template in the Visual Studio installation directory.
When you add a .tt file to a Visual Studio solution, the IDE will automatically assign the .tt file a custom tool setting of TextTemplatingFileGenerator. You’ve already seen this behavior if you created the Simple.tt template I discussed earlier. However, this is not the proper setting for the MVC T4 Templates. The MVC tools for Visual Studio will invoke these templates at the appropriate times and create the special MvcTextTemplateHost object during template processing. Thus, after copying the templates into your project, the second step is to open the Properties Window for each template file and remove the Custom Tool setting (leave the setting blank). At this point you’re ready to customize your templates.
As an example, let’s say you do not want your controllers to have an Index action. You’d rather use a default action named List. You can open up the Controller.tt template in the CodeTemplates\AddController folder and change the appropriate area of code to look like the following:
public class <#= mvcHost.ControllerName #> : Controller
{
// GET: /<#= mvcHost.ControllerRootName #>/
public ActionResult List()
{
return View();
}
...
This is a simple change to make, but it can save you and your team quite a bit of time over the life of a large project.
One Step Further—T4MVC
In the summer of 2009, David Ebbo of the ASP.NET team created T4MVC, a T4 template designed to generate strongly typed helpers in an ASP.NET MVC application. Ebbo has refined the template over time and you can now download it from aspnet.codeplex.com/wikipage?title=T4mvc.
The T4MVC template is a traditional T4 template. You add T4MVC.tt and its associated settings file (T4MVC.settings.t4) to your project and it will use the TextTemplatingFileGenerator custom tool to generate C# code. T4MVC will help you eliminate many of the magic string literals from your MVC application. For example, one of the jobs the template will do is to scan the Content and Scripts folders in your project and generate classes with static properties to represent each script and piece of content.
The generated code means you can render the LogOnUserControl partial view provided by the default MVC project with this code:
<% Html.RenderPartial(MVC.Shared.Views.LogOnUserControl); %>
Previously you would have used a string literal:
<% Html.RenderPartial("LogOnUserControl"); %>
If someone renames, moves, or deletes the LogonUserControl, the strongly typed code will produce a compilation error when the view compiles. In addition to strongly typed access to views and partial views, the T4MVC template also provides strongly typed access to all files inside your Content and Scripts folders and strongly typed access to controllers and controller actions.
You can use the T4MVC-generated classes when building action links, returning view results, and even when building the routing table for an application. Note that when you first add T4MVC to your project, you’ll see some warnings generated in the IDE’s Error List window. These warnings are just T4MVC telling you about some changes it is applying to your code. Most of these changes are nothing that will change the behavior of your application; the T4MVC templates just add some partial keywords to controller class definitions and will also make non-virtual action methods virtual. For more information on T4MVC, check out Ebbo’s blog at blogs.msdn.com/davidebb.
Easier to Maintain
T4 is a wonderful treasure inside of Visual Studio but is still not well-publicized. This article gives you everything you need to get started with custom templates for your ASP.NET MVC project. Hopefully, you can find some uses for T4 Templates outside of your Web application project, too. You should also try out the T4MVC templates in your project, as they make your code easier to maintain and refactor. Moving forward, T4 technology is even better in Visual Studio 2010 with the addition of dedicated item templates and pre-compiled templates.
K. Scott Allen is the principal consultant and founder of OdeToCode, and also a member of the Pluralsight technical staff. You can reach Allen through his blog (odetocode.com/blogs/scott) or on Twitter (twitter.com/OdeToCode).
Thanks to the following technical expert for reviewing this article: David Ebbo
Comments (0)