Two ways to use T4 templates: support code vs. one-time generation

T4 templates have proven to be useful is a whole range of scenarios, and more and more developers are finding interesting things to do with them.

For the most part, all those scenarios fall under two very distinct categories: “support code” versus one-time generation.  Unlike my previous post on CodeDom vs. T4, here we’re not talking about making a choice between two competing technologies, but simply about using T4 in the way that makes sense for a given scenario.

Let’s start with a brief description of the two usage patterns:

Support code: here, a T4 template generates a file that you rarely need to look at, and you should never modify.  Instead, it contains “support code” that you can code against.  A great example of this is my T4MVC template.

One-time generation: here, you are executing a T4 template to generate a file that then becomes part of your project.  This file can then safely be modified.  The T4 template just gave you a starting point.  A great example of this is the Add View dialog in ASP.NET MVC.

I purposely gave two examples that relate to ASP.NET MVC to make a point that the two scenarios are not exclusive, and can play different parts within the same application.

The rest of this post will discuss various aspects of the two scenarios in more details.

 

Using T4 templates to generate “Support Code”

This is the scenario that you are most likely to have encountered when you got introduced to T4 templates.  It has a pretty low barrier of entry as it is directly supported by Visual Studio 2008.  The general flow here is:

  • You add a file with a .tt extension to your VS project
  • VS knows about those files, so it instantly sets it up to use the ‘TextTemplatingFileGenerator’ custom tool (you can see this in the .tt file’s property grid).
  • Whenever you save the .tt file, the template executes, and the generated file becomes a sub-file of the .tt file.

e.g. suppose your Hello.tt file has:

 <#@ Template Language="C#v3.5" #>
<#@ Output Extension=".cs" #>

public static class Hello {
    public static void SayHello() {
<# for (int i=0; i<5; i++) { #>
        System.Console.WriteLine("Hello <#= i #>");
<# } #>
    }
}

In the solution explorer, you will see:

image

And Hello.cs will contain:

 public static class Hello {
    public static void SayHello() {
        System.Console.WriteLine("Hello 0");
        System.Console.WriteLine("Hello 1");
        System.Console.WriteLine("Hello 2");
        System.Console.WriteLine("Hello 3");
        System.Console.WriteLine("Hello 4");
    }
}

Pretty simplistic stuff as far as code generation goes, but there are some key points that need to be made about it.

First and foremost, you should never modify the generated file.  You certainly can go in there and make changes, and no one will stop you.  You can even run your project and your hand modified code will execute.  But guess what will happen the next time you open Hello.tt and save it?  It will re-execute and blow away your carefully modified Hello.cs.  So resist the temptation, and don’t mess with the generated file!

That’s why I named this scenario “Support Code”.  What gets generated is code that is meant to be used by you in the rest of your app.  e.g. in the example above, you could simply call Hello.SayHello() from your console app’s Main.

Now you can take a look at the T4MVC template, which has 1000 lines and does pretty complex things to make it easier to write your MVC app.  But in essence, it works the exact same way as this trivial example: it’s a .tt file which generates a .cs file.  You rarely look at the .cs file, and you never modify it, but instead you call into the bits and pieces that it generates from your controllers and views.  It will frequently regenerate as you project changes, and that’s really the whole point: it keeps itself up to date so you don’t code against stale code.

 

Using T4 files for one-time generation

In this scenario, our purpose is to help the user create a new file for their project by pre-generating it with some useful content instead of having them start with some generic empty file.

As mentioned above, a great example of this is the ASP.NET MVC Add View functionality.  It is described in quite some detail in this post, so you may want to check it out.  I’ll use this as an illustration in this section, though of course a similar technique can be applied to other domains.  Here the general flow is:

  • You would like to generate a new View for their app

  • Instead of giving you a generic new view (which a regular item template would do), it asks you a bunch of questions:

    • What kind of view would you like, e.g. List, Details, Edit, …
    • What kind of entity is it for, e.g. Product, Customer, …
    • What master page you want to use, etc…
  • It takes all that knowledge and feeds it into a T4 template (suing a custom T4 host; a bit more on this later), which generates the view and adds it where it belongs in your project

In both the “Support Code” scenario and here, a T4 file is used to generate another file, but from here on things become totally different.  In this one-time generation scenario, the resulting file becomes a completely normal file that’s part of your project.  As such, you can freely modify it without fear of it getting overwritten, since the T4 template is no longer in the picture.  It was simply used to create the file to get you started.  It was a “one-time” generation.

One weakness of this model is that you can’t easily rerun the template.  e.g. suppose your Product class gets a new member and you want to update the view to account for it.  If you hadn’t touched to previous generated view, you can certainly delete it and rerun the Add View dialog.  But if you had made any modifications, you’re mostly out of luck, and probably better off updating your view by hand without help from the T4 template.  In spite of this weakness, the model is still very useful to get the user quickly started with their code and guiding them towards the pit of success.

Note that I didn’t say much about exactly how the T4 template gets executed in this scenario.  Unlike the “Support Code” scenario, VS is not the one doing it.  Instead, you have to do some things that are a bit more involved to make it happen.  I won’t go into details about how to write a custom T4 host here as it is beyond the scope of this post, and is well covered by other posts (in particular, check out Oleg Sych’s blog).

One last thing I’ll mention about this model is that the .tt file is normally not part of your project.  Instead, it lives somewhere else, and only its output becomes part of your project.  Well, technically, the .tt file can be in your project for easy editing, but you then have to remove the ‘TextTemplatingFileGenerator’ custom tool, because you really don’t want it to execute on its own (it would surely fail with the custom host).

 

Conclusion

To reemphasize what I said early on, these are not two scenarios that compete with each other and for which you must “pick a side”.  They are just two completely different ways of making use of T4 files.  Both are being used successfully in various projects, and they can live together happily ever after :)