Text Templates in Microsoft Visual Studio

Introduction

T4, which stands for Text Template Transformation Toolkit is a code generator build into Visual Studio (available in 2008 and 2010 Standard editions or higher). It allows you to build text files out of templates, using C# or VB.NET as "scripting" languages within the template. In this article I will provide an introduction on T4 starting with a simple example and explaining the different parts of the template.

Setting up a simple template

Let's assume we want to "import" constants (#defines) from a C++ header file into a C# project. The header file, called Constants.h, looks like this:

#pragma once

// here are the values
#define VALUE1 1
#define VALUE2 2
#define VALUE3 10
#define VALUE4 20
// this depends on the previous value
#define VALUE5 VALUE4+1

The file we want to generate in C# out of this header file should look like this:

using System;

namespace T4Demo
{
   public static class Constants
   {
      // here are the values
      public const int VALUE1 = 1;
      public const int VALUE2 = 2;
      public const int VALUE3 = 10;
      public const int VALUE4 = 20;
      // this depends on the previous value
      public const int VALUE5 = VALUE4+1;
   }
}

Note: if you wonder why you would want to do something like this, imagine a project where you want to access features from a native library from managed code. You need to call some native functions and provide some numerical values that are defined in some header, and those values change relatively often. You don't want to update manually those constants in C#, having them updated automatically in the managed project when the native project changes could be a great help.

Using Visual Studio 2008 or 2010 Standard or higher we can add a text template file (having the extension .tt) to the project. Let's call it Constants.tt.

Constants.tt.

The final template that generates the C# Constants class would look like this:

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ import namespace="System.IO" #>
using System;

namespace T4Demo
{
   public static class Constants
   {
<#
      using(StreamReader reader = File.OpenText(Host.ResolvePath(@"constants.h")))
      {
         string line = null;
         while((line = reader.ReadLine()) != null)
         {
            if(line.StartsWith("#pragma"))
            {
               // ignore
            }
            else if(line.StartsWith("//"))
            {
               // comment
#>
      <#=line#>
<#
            }
            else if(line.StartsWith("#define"))
            {
               string []parts = line.Split(new char[]{' '});
               if(parts != null && parts.Length >= 3)
               {
                  // part 1 is #define, part 2 is name, part 3 is value
                  string name = Normalize(parts[1]);
                  string value = Normalize(parts[2]);
#>
      public const int <#=parts[1]#> = <#=value#>;
<#                  
               }
            }
         }
      }
#>
   }
}
<#+
   string Normalize(string value)
   {
      return value.Trim();
   }
#>

Unfortunately, Microsoft Visual Studio doesn't have syntax highlighting or IntelliSense for text templates. So when you open a text template, it looks like this:

text template

The good news is that free advanced editors are available. One of them is Visual T4 Editor Community edition from Clarius. Another one is tangible T4 Editor plus modeling tools for VS2010 from tangible, available also in the Visual Studio Gallery. Here is how the text template looks with the tangible T4 editor:

tangible T4 editor:text template

When you add and build the first text template file, Visual Studio will show you a warning:

T4 Warning

This is because being a template it could contain potential harming code. Check "Do not show this message again" and press OK. If you want to get this warning again later, go to Tools > Options > Text Templating and set the Show Security Message property to True.



Text Templates in Microsoft Visual Studio

Directives

Let's analyze the template now. You can see that the file contains some text (which happens to be .NET code, but in fact it can be anything) and C# code within <# and #>. Actually within the T4 tags <# and #> there are directives, statements, class features and expressions. The directives in our file are:

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ import namespace="System.IO" #>

The directives seen above, template, output and import are three of the 6 standard directives available.

  • template: allows to specify some aspects of the transformation, such as the language used in statements, class features and expressions, whether debugging is enabled or not, access to the host of the transformation engine, etc. When using Visual Studio and hostspecific is set to true, we can cast the Host property to IServiceProvider to access Visual Studio features. Also we can use Host.ResolvePath(filename) to resolve the absolute path of a file in the project (or from a path relative to the project). In our example we have specified that we use C#, we want access to the host of the transformation engine, and debugging should not be enabled.
  • output: allows to specify the extension and the encoding of the generated file. We have specified that the generated file is a C# file.
  • import: allows to access elements from a namespace without using the fully qualified name. This is equivalent to the using directive from C#. We have specified that we want to import the System.IO namespace (for stream operations).
  • include: allows to add text from a specified template file within the current template file (basically merging them).
  • assembly: allows to load an assembly so that we can use types from it. This is similar to adding a reference to a Visual Studio project.
  • parameter: allows to define properties in the template initialized with values from external contexts.

For more information about the standard directives see MSDN.

Class features

Class features are helper functions you can define in a text template to reuse code. They are introduced within the opening <#+ and closing #> and must appear after all the directives and all the statements in the text block. You can see a class feature at the end of the template. This function doesn't do anything special, it's provided only for didactic reasons.

<#+
   string Normalize(string value)
   {
      return value.Trim();
   }
#>

You can read more about class features in MSDN.

Statements

The template can contain any statements written in C# or VB.NET (depending on the language specified with the template directive). However, they must be enclosed within <# and #> and must appear after all the directives and before any class feature.

Most of the code below is made of statements. What we do is opening the Constants.h file and read every line. We ignore the #pragma directive, but any line that starts with // and thus represents a comment is written in the output file. Any line that starts with #define is split and its parts are used to generate a new line in the output .cs file. For the sake of simplicity we keep the format of the C++ header file simple, with just one space between #define and the name and one space between the name and the value. If you add other spaces there it will break the code. Notice that we call the helper function Normalize() defined with a class feature at the end of the file (after the statements where it is used).

<#
      using(StreamReader reader = File.OpenText(Host.ResolvePath(@"constants.h")))
      {
         string line = null;
         while((line = reader.ReadLine()) != null)
         {
            if(line.StartsWith("#pragma"))
            {
               // ignore
            }
            else if(line.StartsWith("//"))
            {
               // comment
#>
      <#=line#>
<#
            }
            else if(line.StartsWith("#define"))
            {
               string []parts = line.Split(new char[]{' '});
               if(parts != null && parts.Length >= 3)
               {
                  // part 1 is #define, part 2 is name, part 3 is value
                  string name = Normalize(parts[1]);
                  string value = Normalize(parts[2]);
#>
      public const int <#=parts[1]#> = <#=value#>;
<#                  
               }
            }
         }
      }
#>

You can read more about statements in MSDN.

Expressions

If you looked carefully at the code above you probably noticed another set of tags, <#= and #>. These are expression blocks that allow you to put strings into the output files.

The raw text below contains two expression block, used to print the name of the constant and the value of the constant. They are defined in the statement block above.

public const int <#=parts[1]#> = <#=value#>;

You can read more about expression blocks in MSDN.

Putting all together

Having defined the text template show earlier we can obtain the transformation we wanted at the beginning of the article. The file Constants.cs is now part of the C# project and the class Constants can be used just like any other type from the project.

[t4demo.png]

namespace T4Demo
{
   class Program
   {
      static void Main(string[] args)
      {
         Console.WriteLine(Constants.VALUE5);
      }
   }
}

How to use text templates in VC++

Unfortunately text templates are not directly supported in Visual C++. There is however a workaround with Custom Builds to use them. Here is what you can do to add and build text templates in VC++.

  • Add a new text file to your project. Change the extension from .txt to .tt. Let's call the file sample.tt.
  • Select the .tt file and open its Properties page. In the Configuration Properties, change the value of the Item Type from "Does not participate in build" to "Custom Build Tool".
  • After you press Apply a new tab should appear, Custom Build Tool. Open it and set a value for Command Line to "C:\Program Files (x86)\Common Files\Microsoft Shared\TextTemplating\10.0\TextTransform.exe" sample.tt (make sure you specify the correct path of the TextTransform.exe tool, followed by the name of the text template file to build). Set the Outputs property to the name of the output file, for instance sample.h (if you want to generate a header file).
  • Compile the file.

Conclusions

Text templates are a powerful and helpful mechanism available in Visual Studio to generate text files from templates using C# or VB.NET as "scripting" languages. The syntax is simple and though Visual Studio does not provide advance editor (with syntax highlighting or intellisense) free 3rd party solutions are available. See the References sections for additional readings.

References

Related Articles





About the Author

Marius Bancila

Marius Bancila is a Microsoft MVP for VC++. He works as a software developer for a Norwegian-based company. He is mainly focused on building desktop applications with MFC and VC#. He keeps a blog at www.mariusbancila.ro/blog, focused on Windows programming. He is the co-founder of codexpert.ro, a community for Romanian C++/VC++ programmers.

Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Hurricane Sandy was one of the most destructive natural disasters that the United States has ever experienced. Read this success story to learn how Datto protected its partners and their customers with proactive business continuity planning, heroic employee efforts, and the right mix of technology and support. With storm surges over 12 feet, winds that exceeded 90 mph, and a diameter spanning more than 900 miles, Sandy resulted in power outages to approximately 7.5 million people, and caused an estimated $50 …

  • Live Event Date: April 22, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Database professionals — whether developers or DBAs — can often save valuable time by learning to get the most from their new or existing productivity tools. Whether you're responsible for managing database projects, performing database health checks and reporting, analyzing code, or measuring software engineering metrics, it's likely you're not taking advantage of some of the lesser-known features of Toad from Dell. Attend this live …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds