Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Auto Transform T4 (Text Template Transformation Toolkit) Templates on Project Build

4.00/5 (2 votes)
3 Jul 2019CPOL3 min read 16.6K   179  
This article describes an advanced technique and configuration to automatically transform and run your all or selected T4 templates when a project is build.

Introduction

This article describes how we can configure and mandate auto transformation of a text or code in the project when a build happens.

In Visual Studio, a T4 text template is a mixture of text blocks and control logic that can generate a text file.

The generated file can be text of any kind, such as a web page, or a resource file, or program source code in any language.

You can select all templates to execute or only specific ones whenever a Project/Solution Build.

It's useful when T4 templates generate text from dynamic data and help collaborate team members. There may be a situation where T4 templates get data from database and code is generated based on that data. In Source control environment where there are multiple check ins by multiple developers, this could really be an important piece of work where we could mandate/enforce auto transform for consistency and help resolve merge conflict in advance.

There might be a situation where developers ignore manual transformation of T4 templates but still modify the data which leaves the code in inconsistent stage.

Auto transform could also be integrated to existing CI/CD process.

Background

  • Auto execute T4 template on build
  • Show pre and post transformation messages and list of files
  • Select specific or all T4 files for auto transform

Using the Code

  1. Download the attached project.
  2. Modify the csproj file to add transformation to html2 and remove it from html1 and see the result.
  3. Build (Currently the project is configured to transform only html1).
  4. Look for messages in Output window.

Steps involved and details below:

Start with creating a new console application or web application:

Click to enlarge image

For demo, we will use HTML Generators which generate .html file containing datetime.

Add 2 new Text templates, HtmlGenerator1.tt and HtmlGenerator2.tt.

Click to enlarge image

Add the below code in the .tt files.

HtmlGenerator1.tt:

HTML
<#@ output extension=".html" #>

<html>
<body>
HTML Generator 1
 The date and time now is: <#= DateTime.Now #>
</body>
</html>

HtmlGenerator2.tt:

ASP.NET
<#@ output extension=".html" #>

<html>
<body>
HTML Generator 2
 The date and time now is: <#= DateTime.Now #>
</body>
</html>

The only code to execute in this HTML template will be DateTime.Now.

In real life, this could be enums generating from database data, C# code generating from a for loop, complete email template, etc.

Now let's run a template:

Image 3

The HTML file is generated as below:

HTML
<html>
<body>
HTML Generator 1
 The date and time now is: 06/25/2019 15:44:44
</body>
</html>
HTML
<html>
<body>
HTML Generator 2
 The date and time now is: 06/25/2019 15:44:44
</body>
</html>

Note that both the times are the same because I executed both templates together at the same time.

Let's configure HtmlGenerator1 to be auto transform whenever we do a rebuild and keep HtmlGenerator2 on its own. This would mean on build, the time will be updated for HtmlGenerator1 but not for HtmlGenerator2.

Edit the project and use the below configs:

 

XML
<Import Project="$(VSToolsPath)\TextTemplating\Microsoft.TextTemplating.targets" />

Run the Transform task at the start of every build. Simply switch it off to disable auto transform on build.

C#
TransformOnBuild=true

Overwrite files that are read-only, for example because they are not checked out.

C#
OverwriteReadOnlyOutputFiles=true

Transform every template every time:

C#
TransformOutOfDateOnly=false

 

Complete Configuration below:

XML
<!-- START AdvancedT4Techniques -->
  <!-- START Configuration: Define some methods to execute 
       before and after the transform to show some messages. -->
  <PropertyGroup>
    <BeforeTransform>CustomPreTransform</BeforeTransform>
    <AfterTransform>CustomPostTransform</AfterTransform>
  </PropertyGroup>
  <Target Name="CustomPreTransform">
    <Message Text="In CustomPreTransform..." Importance="High" />
    <!-- This message will be shown in Output window right before the transformation -->
  </Target>
  <Target Name="CustomPostTransform">
    <Message Text="In CustomPostTransform...@(GeneratedFiles)" Importance="High" />
    <!-- This message will be shown in Output window right before the transformation. 
         It also shows the Generated Files. -->
  </Target>
  <!-- END Configuration -->
  <!-- START Auto Execute T4 template -->
  <!-- Optionally make the import portable across VS versions -->
  <PropertyGroup>
    <!-- Get the Visual Studio version: -->
    <VisualStudioVersion Condition="
    '$(VisualStudioVersion)' == ''">16.0</VisualStudioVersion>
    <!-- Keep the next element all on one line: -->
    <VSToolsPath Condition="'$(VSToolsPath)' == ''">
    $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
  </PropertyGroup>
  <Import Project="$(VSToolsPath)\TextTemplating\Microsoft.TextTemplating.targets" />
  <!-- Below settings will control if we want to auto transform on build -->
  <PropertyGroup>
    <TransformOnBuild>true</TransformOnBuild>
    <!-- Run the Transform task at the start of every build. 
         Simply switch it off to disable auto transform on build. -->
  </PropertyGroup>
  <PropertyGroup>
    <OverwriteReadOnlyOutputFiles>true</OverwriteReadOnlyOutputFiles>
    <!-- Overwrite files that are read-only, for example because they are not checked out -->
  </PropertyGroup>
  <PropertyGroup>
    <TransformOutOfDateOnly>false</TransformOutOfDateOnly>
    <!-- Transform every template every time -->
  </PropertyGroup>
  <!-- Below settings are to select the files which needs to be transformed automatically-->
  <Target Name="CreateT4ItemLists">
    <Message Importance="low" Text="Creating T4 items lists for 
     project $(ProjectName) ($(ProjectPath))..." />
    <!-- Work out which of the files in the @(CreateT4ItemListsInputs) group are T4 files. -->
    <ItemGroup>
      <!-- Add only those files that have the AutoTransformOnBuild marked as true.
           This way you could select specific T4 templates to be auto transform on build 
           while excluding others. -->
      <T4TransformInputs Include="@(CreateT4ItemListsInputs)" 
       Condition=" %(CreateT4ItemListsInputs.AutoTransformOnBuild) == true " />
      <!-- Add any files that are in the gruop T4Transform -->
      <T4TransformInputs Include="@(T4Transform)" />
    </ItemGroup>
  </Target>
  <!-- End Auto Execute T4 template -->
  <!-- END AdvancedT4Techniques -->

Results

Image 4

Image 5

Points of Interest

  • With CI/CD already configured to build the project, it will automatically execute the T4 template and merge conflicts can be handled when the code is committed.
  • Enforcing policies in the project is easy, important messages can be written in the output window.

History

  • Initial version published
  • Attached project files and github link

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)