After exploring the theoretical side of an automation project over the last few weeks, it is now time to get our hands dirty and write some code. There are many options for code generation, but I prefer the T4 templates. We have been using them for years and they are so stable that they form an excellent basis for our automation project.
What is T4?
Microsoft introduced the Text Template Transformation Toolkit (short T4) in 2005. If you generated controllers, view models or anything else in Visual Studio since then, you did run a T4 template – probably without knowing it.
We can use C# to create any text file we want with T4: XML, C#, Python, JSON, HTML, and everything else that uses a text file. The C# we use in the template is there to give us the flexibility and the logic, while the output we produce is text.
You can find the code of T4 itself on GitHub.
Installation
If you use Visual Studio or Rider, you do not need to install T4. It comes with those two development environments and works out of the box.
For Linux or other editors, you can install T4 as a global dotnet tool with this command:
1 |
dotnet tool install --global dotnet-t4 --version 2.3.1 |
Our first template
For our first steps with T4 we use this little template named basic.tt to create an HTML file with the current date in it – that is the date at the time we run the template to generate the HTML code:
1 2 3 4 5 6 |
<#@ template debug="false" hostspecific="true" language="C#" #> <#@ output extension=".html" #> <html><body> The date and time now is: <#= DateTime.Now #> </body></html> |
Make sure that the Custom Tool points to TextTemplatingFileGenerator in the properties of the T4 template:
Run the code generator
In Visual Studio we can right-click on the template and generate the code with the option “Run Custom Tool“:
In Rider we can right-click on the template and use the option “Run Template” to generate the code:
On Linux we can use this command to generate the code from our T4 template:
1 |
t4 basic.tt |
Whatever option you choose to generate the code, our first template should contain a small HTML fragment with the date of the template run:
1 2 3 |
<html><body> The date and time now is: 04/22/2024 21:43:50 </body></html> |
A more complex template
When we want to generate code, we need a bit more logic inside our template. We can use two lists, one with the name of the classes we want to generate, and the other list with the fields and their types. In our template we need a bit of glue code, a few assembly references and then we can loop through both lists:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<#@ template debug="false" hostspecific="true" language="C#" #> <#@ assembly name="System.Core" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Text" #> <#@ import namespace="System.Collections.Generic" #> <#@ output extension=".cs" #> <# var classes = new string[] { "OrderDto", "ProductDto" }; var fields = new List<Tuple<string, string>>{new ("Id", "int"), new ("Name", "string"), new ("IsActive","bool")}; foreach(var name in classes) { #> namespace Test.TestSubFolder { public class <#= name #> { <# foreach(var field in fields) { #> public <#= field.Item2#> <#= field.Item1 #> { get; set; } <# } #> } } <# }; #> |
If we run the custom tool for our template, we get a ClassGenerator.cs file with our two classes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
namespace Test.TestSubFolder { public class OrderDto { public int Id { get; set; } public string Name { get; set; } public bool IsActive { get; set; } } } namespace Test.TestSubFolder { public class ProductDto { public int Id { get; set; } public string Name { get; set; } public bool IsActive { get; set; } } } |
Documentation and help
Microsoft offers us a good documentation for T4 that covers most of the things we need to know about T4.
In the article on T4 in Wikipedia we get this handy table of the 4 control types of T4:
Name | Syntax | Description |
---|---|---|
Directives | <#@ … #> | Instructions for the transformation engine |
Standard control blocks | <# … #> | Code to be executed (e.g. loops) |
Expression control blocks | <#= … #> | Expressions evaluated and converted to a string |
Class feature control blocks | <#+ … #> | Class and function definitions |
A good source of help for problems with T4 is Stack Overflow. If you cannot find an answer there, use your favourite search engine and do not ignore older search results. T4 did not change much over the last years and an old post may still be helpful.
Shortcomings
The main shortcoming of T4 is that it creates its output into a single file. While we can use the code that way, it is most likely something we never would allow our teammates to do. Next week we find a solution for that problem that allows us to create our code into separate files.
The not so obvious shortcoming is that T4 has all the features it needs. Therefore, we do not get new versions that often and you have a hard time to figure out what version you use in the first place. This gives the impression of a dead technology, but that is not true. T4 is alive and kicking and you can run it on Windows, Linux, Mac, with the .Net full framework and .Net (Core).
Next
With our two T4 templates we could get a first impression of this helpful technology. We can use C# code to generate anything that uses a text file as its base. The options are nearly endless and help us for our automation project. Next week we address the main shortcoming of T4 and generate code into different files.
2 thoughts on “Automate Code Generation With T4 Templates”