By default in T4, the code generation (a.k.a. template transformation) occurs when you save a template (.tt) file or select Run Custom Tool from its context menu in Solution Explorer. This works very well while you are actively developing the code generator, making changes in the template file and saving it to see the generated code. However, once development of the code generator itself is finished and your entire development team begins using it, this way of triggering code generation becomes less than ideal.
If your template generates code from metadata stored in a separate file, such as the LINQ to SQL .dbml file, it is easy for a developer to change the input file and forget to regenerate the code using the code generator in a separate T4 file. This mistake can lead to unnecessary frustration and wasted effort, especially when a T4-based code generator replaces a built-in code generator, such as MSLinqToSqlGenerator, which generates code automatically whenever the input file is saved.
You can eliminate the waste of effort and frustration by triggering your T4-based code generator automatically, whenever the input file is saved. This can be accomplished using a proven Visual Studio extensibility mechanism – Custom Tools. In this article, we will review how you can create your own custom tool or simply use the one provided by the T4 Toolbox.
A custom tool - sometimes referred to as a single file generator - can be used to extend the Visual Basic, Visual C#, and Visual J# project systems in Visual Studio. A custom tool is a COM component that implements the IVsSingleFileGenerator interface. Using this interface, a custom tool transforms a single input file into a single output file. The result of the transformation may be source code, or any other output that is required. T4 itself provides a custom tool called TextTemplatingFileGenerator, which is automatically associated with .tt files and performs template transformation. Before you can use a custom tool, you must register it with the system or in the Visual Studio local registry. You can find complete details about custom tools and single file generators in Visual Studio SDK.
T4-Based Custom Tool
One way to automate T4-based code generation, is to create a custom tool that will be associated with your input file. When the input file is modified, Visual Studio will invoke this custom tool; the tool will load a T4 template either from an embedded resource or an external file and use ITextTemplating service to generate the code.
There are different ways to implement such custom tool. If you are building a modeling solution using Domain-Specific Language tools, Jean-Mark Prieur provides an excellent example in Part 4 of the DSL Tools Lab. Alternatively, you can follow instructions in Visual Studio SDK, which requires more work, but does not have a dependency on DSL toolkit. Either way, you will want to take advantage of the built-in functionality provided by T4 and inherit your custom tool from the TemplatedCodeGenerator as Jean-Mark suggests.
Although implementing a T4-based custom tool is not difficult, the custom tool requires registration, which means having an installation program. If you are a tool developer, this is not a problem – you probably already have one. If you are an application developer, this is just another bit of extra work that doesn’t directly contribute to your product, the extra work you want to avoid.
T4 Toolbox (version 9.10 or later) provides a ready-to-use custom tool called T4ScriptFileGenerator. You can associate it with a particular file using Solution Explorer and Properties window as shown below.
First time you save the input file (Northwind.dbml in our example) after assigning T4ScriptFileGenerator as its Custom Tool, it will create an empty .tt file similar to this.
<#@ template language="C#" hostspecific="True" debug="True" #> <#@ output extension="txt" #> <#@ include file="T4Toolbox.tt" #>
Note that the new .tt file has the usual TextTemplatingFileGenerator custom tool associated with it.
When you add the actual code generation logic and save this file, T4 engine will transform it automatically, as you would expect. In this example, we will modify Northwind.tt file to look like this.
<#@ template language="C#v3.5" hostspecific="True" #> <#@ output extension="log" #> <#@ include file="T4Toolbox.tt" #> <#@ include file="T4Toolbox\LinqToSql.tt" #> <# LinqToSqlGenerator generator = new LinqToSqlGenerator(); generator.DbmlFile = "Northwind.dbml"; generator.Run(); #>
Now if we go back and modify our input file, Northwind.dbml, the T4ScriptFileGenerator will reuse the existing T4 script, Northwind.tt, and trigger the code generation. In other words, the Northwind.tt file is being transformed automatically whenever we change the input file, Northwind.dbml.
This configuration process is easy to follow and once you are done, simply check your project into your source control and the custom tool configuration will be preserved in the project file itself. To begin using this code generator, other developers on your team simply need to have T4 Toolbox installed on their computers and get latest version of the project source code.
However, if you are building T4-based code generators that can be created and configured by others, perhaps your development team or external customers, you may want to save them the trouble of performing these steps manually every time they need to create a new code generator.
T4 Toolbox (version 9.12 or later) also allows you to automatically associate T4ScriptFileGenerator with an input file using a Visual Studio Project Item Template. Simply put both the input file and the code generation script (.tt) file in the template as described in the article mentioned above and provide a VSTEMPLATE file similar to this.
<VSTemplate Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" Type="Item"> <TemplateData> <DefaultName>DataClasses.dbml</DefaultName> <Name>LINQ to SQL Model</Name> <Description>LINQ to SQL entity classes and schema objects.</Description> <ProjectType>CSharp</ProjectType> </TemplateData> <TemplateContent> <References> <Reference><Assembly>System</Assembly></Reference> <Reference><Assembly>System.Core</Assembly></Reference> <Reference><Assembly>System.Data.Linq</Assembly></Reference> </References> <ProjectItem SubType="Designer" TargetFileName="$fileinputname$.dbml" ReplaceParameters="true">Dbml.xml</ProjectItem> <ProjectItem SubType="" TargetFileName="$fileinputname$.tt" ReplaceParameters="true">LinqToSqlModel.tt</ProjectItem> </TemplateContent> <WizardExtension> <Assembly>T4Toolbox, Version=220.127.116.11, Culture=neutral, PublicKeyToken=7e313accbcce84dc</Assembly> <FullClassName>T4Toolbox.VisualStudio.T4ScriptFileGeneratorWizard</FullClassName> </WizardExtension> </VSTemplate>
Notice the use of <WizardExtension/> to associate the T4ScriptFileGenerationWizard with this project item template. This wizard extension will assign T4ScriptFileGenerator as a custom tool to the root item unfolded by the template - $fileinputname$.dbml or Northwind.dbml file in this example. If the project item template contains a T4 script file with the matching name ($fileinputname$.tt), the wizard extension will also make sure the code in it is preserved and used for code generation. If the project item template does not contain a T4 script file, an empty .tt file will be created instead.
Remember that T4 Toolbox has a separate assemblies for Visual Studio 2008 (T4Toolbox.dll) and Visual Studio 2010 (T4Toolbox.10.0.dll). The VSTEMPLATE example above is for Visual Studio 2008. In 2010, you have to change the <WizardExtension> to look like this.
<WizardExtension> <Assembly>T4Toolbox.10.0, Version=18.104.22.168, Culture=neutral, PublicKeyToken=7e313accbcce84dc</Assembly> <FullClassName>T4Toolbox.VisualStudio.T4ScriptFileGeneratorWizard</FullClassName> </WizardExtension>
As you have already guessed, T4 Toolbox uses T4ScriptFileGenerator and T4ScriptFileGeneratorWizard in its LINQ to SQL model sample code generator for C#. You can see it in action yourself.
Although the built-in mechanism for triggering template transformation in T4 works well during development of a code generator, it often leads to mistakes during its normal use, when developers primarily modify the code generation model or input file. There are different ways of triggering the code generation automatically when the input file changes. In this article we discussed one of these approaches, based on Custom Tools. While it is possible to completely hide code generation from developers with this approach, doing so would prevent developers from being able to take advantage of rich template-based customization capabilities offered by T4. The T4ScriptFileGenerator in T4 Toolbox allows you get the best of both options: have the code generation occur automatically when the input file changes and still allow developers to customize the code generator by changing the T4 template.