Autogenerate Code Using T4 in VS 2010
The Text Template Transformation Toolkit, or T4 is a solution that reduces the repetitive work of a developer by creating a template that auto-generates code from a set of rules, other code, or data input
Friday, July 16, 2010
BANGALORE, INDIA: If you look at the work that a normal developer does most of the time, it's a fairly repetitive job wherein he writes code for doing a particular module which is similar to everything else that is done with small differences being say, the fields that need to be displayed/updated to a different table in a different database. There are many other things that are similar as well.
However, there is a way to not just automate this work so that the developer has to only fill in the requirements and the code gets generated, but also ensure that the code is up to standards as defined by policy. This can make the architect's and project manager's, not to mention the developer's life also much better. There is a technology in the .NET world that allows you to do this called T4.
T4 is an abbreviation for Text Template Transformation Toolkit. This is way of writing a 'template' that can generate code from a set of rules, other code, or data input. You can write a template that can be used multiple times with a slight change in input which will output code for different scenarios. Fairly complex scenarios are possible by using this. Let's start with some simple examples and then move on to some more complex ones to see how they work.
First of all, fire up Visual Studio 2010 (or Visual Studio 2008 with the free T4 Toolbox installed). Note that in VS2008, you will not see an item type in the new item list and will need to create a text file yourself. In VS2010, simply create an 'Empty Project' and then add a new item of type 'Text Template'. This will create a new file with the extension of '.TT'. When the file opens in VS, you will see the following lines:
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".txt" #>
There are a couple of things to note here. The language attribute in the first line specifies that language that is going to be used for creating the template ? not the language that is the output. The extension attribute in the second line specifies the type of file that is going to be generated. Expand the .TT file you created in Solution Explorer and you'll see a .TXT file with the same name. Now change the value in the extension to say '.cs' and it will change the file as well. Change the .TT file to the following:
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>
using System;
namespace Hello
{
class Program
{
public void Main()
{ Console.WriteLine("Hello World"); }}}
As soon as you save the file, open up the associated .CS file. You should see the entire code (other than the T4 directives at the top) generated for you. Congrats, you've just auto-generated your first piece of code.
Text Template item type in VS 2010
However, this is not really impressive right now. You've actually written more than what the code actually is. But think of a case where you might need to write this exact same code out, but just change the message that is shown. For this, you now need to start writing T4 code itself to allow the template to accept parameters and use them in the code generation.
Modify the code above by changing the Writeline line and adding the following:
{ Console.WriteLine("<#= this.Message #>");}}}
<#+
string Message = "Hi There";
#>
When you save this file and open the .CS one, you will see that the message has indeed changed. The '<#=' and the '<#+' signs are some T4 directives to tell the T4 compiler what needs to be done. Now by simply changing the value in the Message variable, you can output different code files each time.
An autogenerated ASP.NET WebForm using a T4 template
You can also include other code files to your own. For instance, you might want to generate this file after some other processing. So create a new .TT file, say MyTest1.tt and have the following within it:
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>
<#
this.Message = "Hallo Welt!";
#>
<#@ include file="HelloWorld.tt" #>
Open the MyTest1.cs file, and you'll find a German version of the 'Hello World' message. You can of course go ahead and generate a bunch of code more complex than this of course. As an example, let's take a look at some templates that automatically generate ASP.NET files - both ASPX and ASPX.CS - for working with a database table. For code generation, the developer simply needs to change an XML file that defines the table and the fields.
A number of T4 template files are needed in this case:
1.WebFormFields.tt: Generates the frontend ASPX and HTML code
2.CodeBehindFields.tt: Generates backend database connectivity code (for this article only displays field name)
3.SaveOutput.tt: Saves the ASPX and ASPX.cs file in the current directory
4.BuildPagesFromXML.tt: Reads the XML file for fields and then uses the other T4 files to generate
The code in each (abbreviated) looks like this:
WebFormFields.tt
<#+ void GenerateASPXField(string FName, string Type, string Choices) { #>
:
<#+ switch (Type) {
case "Text": #>
<#+ break; case "List": #>
<#+ string[] items = Choices.Split(';'); for (int i = 0; i < items.Length; i++) { #>
<#= items[i] #>
<#+ } #>
<#+ break; default: break; }} #>
This code defines a T4 function that simply outputs a textbox and a dropdownlist for fields defined as such in an XML file.
CodeBehindFields.tt
<#+ void GenerateCBFieldSave(string FName, string Type, string Choices) {
switch (Type) {
case "Text": #>
Response.Write("Field <#= FName #>; Value= " + txt<#= FName #>.Text);
<#+ break; case "List": #>
Response.Write("Field <#= FName #>; Value= " + ddl<#= FName #>.SelectedValue);
<#+ break; default: break; } } #>
Another autogenerated Webform using the same T4 template
This defines a T4 function that simply outputs the fieldname and associated value.
SaveOutput.tt
<#@ template language="C#" hostspecific="true" #>
<#@ import namespace="System.IO" #>
<#+
void SaveOutput(string outputFileName)
{
string templateDirectory = Path.GetDirectoryName(Host.TemplateFile);
string outputFilePath = Path.Combine(templateDirectory, outputFileName);
File.WriteAllText(outputFilePath, this.GenerationEnvironment.ToString());
this.GenerationEnvironment.Remove(0, this.GenerationEnvironment.Length);
}
#>
This defines a function that saves both the ASPX and ASPX.cs files when called.
BuildPagesFromXML.tt
This code will need to generate the standard ASP.NET header and footer for both files and also the generated code by including the files above. The main code for generating the fields looks like this:
foreach (XmlNode node in doc.SelectNodes("/Fields/Field"))
{
FieldName = node.Attributes["Name"].InnerText;
Type = node.Attributes["Type"].InnerText;
switch (Type)
{
case "Text":
GenerateASPXField(FieldName, Type, "");
break;
case "List":
GenerateASPXField(FieldName, Type, node.Attributes["Choices"].InnerText);
break;
}
}
SaveOutput(WebFormName + ".aspx");
foreach (XmlNode node in doc.SelectNodes("/Fields/Field"))
{
FieldName = node.Attributes["Name"].InnerText;
Type = node.Attributes["Type"].InnerText;
switch (Type)
{
case "Text":
GenerateCBFieldSave(FieldName, Type, "");
break;
case "List":
GenerateCBFieldSave(FieldName, Type, node.Attributes["Choices"].InnerText);
break;
}
}
SaveOutput(WebFormName + ".aspx.cs");
The input XML file looks like this:
As you change the form name and the fields, a new Name.aspx and Name.aspx.cs files with the correct front and backend code will be generated in the directory. As the entire set of templates was too large for this article, I'll be uploading the solution to the PCQ Forums where you can pick it up.
T4 templates are powerful ways of automating and standardizing code generated in your company's projects. You can use this to enhance productivity as well as let developers work on better value additions to the project that doing the same repetitive job everyday.
©PCQuest
No comments:
Post a Comment