T4 Toolbox: Support for Visual Studio 2010


As of version 9.10, T4 Toolbox now supports Visual Studio 2010 in addition to Visual Studio 2008. You can now create both traditional and preprocessed templates that utilize the advanced functionality the Toolbox offers to generate multiple output files, add them to different projects and more.

The set of project item templates has been extended to support preprocessed templates and generators. Here is what you will see when you add a new item to a Visual Basic project.

image

This list contains familiar project item templates, such as Template, Generator and Unit Test. Script is the project item template that was previously named File. It is a traditional .tt file that is meant to include other, partial .tt files such as Template and Generator. Hopefully the new name Script makes more sense than File.

The list of project item templates for Visual C# projects is similar and also includes ready-to-use code generators written in C#. It is the same with the exception of the Enum SQL View, which at this time works only in Visual Studio 2008.

Preprocessed Templates and Generators

Preprocessed Template and Preprocessed Generator project item templates, which are similar to the traditional Template and Generator respectively, were added take advantage of the new capability offered by Visual Studio 2010 to preprocess .tt files and compile T4-based code generators in .NET assemblies.

When you add a Preprocessed Template to your project, two files get created - a preprocessed .tt file and a partial .cs or .vb file similar to the ones below.

Template.tt (C#)
<#@ template language="C#" inherits="T4Toolbox.Template" #>

Template.partial.cs
namespace ClassLibrary1
{
    using System;
    using T4Toolbox;

    public partial class Template1
    {
        protected override void Validate()
        {
            this.Warning("Template properties have not been validated");
        }
    }
}
Template.tt (Visual Basic)
<#@ template language="VB" inherits="T4Toolbox.Template" #>

Template.partial.vb
Imports T4Toolbox

Partial Public Class Template1
    Inherits Template

    Protected Overrides Sub Validate()
        Me.Warning("Template properties have not been validated")
    End Sub

End Class

For preprocessed .tt files, T4 doesn’t generate actual output; instead it generates the code generation template itself. Here is a cleaned-up version of what you will see if you open the files generated by TextTemplatingFilePreprocessor.

Template.cs
namespace ClassLibrary1
{
    using System;
    using System.CodeDom.Compiler;

    #line 1 "C:\…\Template1.tt"
    [GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "10.0.0.0")]
    public partial class Template1 : T4Toolbox.Template
    {
        public override string TransformText()
        {
            return this.GenerationEnvironment.ToString();
        }
    }

    #line default
    #line hidden
}

Template.vb
Imports System
Imports System.CodeDom.Compiler

<GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "10.0.0.0")> _
Partial Public Class Template1
    Inherits T4Toolbox.Template
    Public Overrides Function TransformText() As String
        Return Me.GenerationEnvironment.ToString
    End Function
End Class

Together, Template and Template.partial files define a single class that descends from T4Toolbox.Template which I assume is already familiar to the reader. In a traditional T4 Toolbox Template, you would place all logic in a single .tt file, using a mix of text blocks and class feature blocks. With a preprocessed template, you will typically want to use the .tt file only for the logic that requires text templating. Non-templating logic, such as validation, properties, utility methods, etc. can be placed in the partial .cs/.vb file. This helps to reduce complexity of .tt files by isolating “presentation” code that requires text templating in its own file where it is not mixed with the class definition and model access code.

Despite of what their name implies, Preprocessed Generator project items are not .tt files. A traditional Generator is typically defined in a single class feature block of a .tt file, does not use any text templating features and uses one or more traditional Templates to generate output files. Similarly, a Preprocessed Generator is a simple .cs/.vb file that contains a Generator class definition and uses one or more Preprocessed Templates to generate output files. Here is what it looks like.

C#
namespace ClassLibrary1
{
    using System;
    using T4Toolbox;

    public class Generator1 : Generator
    {
        protected override void RunCore()
        {

        }

        protected override void Validate()
        {
            this.Warning("Generator properties have not been validated");
        }
    }
}

Visual Basic
Imports T4Toolbox

Public Class Generator1
    Inherits Generator

    Protected Overrides Sub RunCore()

    End Sub

    Protected Overrides Sub Validate()
        Me.Warning("Generator properties have not been validated")
    End Sub

End Class

Just like in a traditional generator, you would typically define several properties and override RunCore and Validate methods.

T4Toolbox.Template Class Has a Breaking Change

In order to be compatible with template preprocessing in Visual Studio 2010, interface and implementation of the T4Toolbox.Template class had to change. TransformText method used to have a sealed implementation that called the abstract RenderCore method you had to override in the descendants. Now the TransformText method itself is abstract and serves the purpose of RenderCore which has been removed.

This is a breaking change for any existing traditional Template classes you may have. Here is an example of a Template implementation you had before.

C#
<#+
public class Template2 : Template
{
    public override void RenderCore()
    {
        // Text blocks and code generation logic
        // …
    }
}
#>

Visual Basic
<#+
Public Class Template2
    Inherits Template

    Public Overrides Sub RenderCore()
        ‘ Text blocks and code generation logic
        ‘ …
    End Sub

End Class
#>

And here is an example of a Template implementation you have to have now.

C#
<#+
public class Template2 : Template
{
    public override string TransformText()
    {
        // Text blocks and code generation logic
        // …
        return this.GenerationEnvironment.ToString();
    }
}
#>

Visual Basic
<#+
Public Class Template2
    Inherits Template

    Public Overrides Function TransformText() As String
        ‘ Text blocks and code generation logic
        ‘ …
        Return Me.GenerationEnvironment.ToString()
    End Function

End Class
#>

In order to be compatible with the new version of T4 Toolbox, all existing Template implementations need to be modified to a) replace each RenderCore method override with a TransformText method override and b) return GenerationEnvironment.ToString() at the end of the method.

Template class now provides a new method called Transform, which returns a string and serves the same purpose as TransformText implementation served previously. Just like TransformText, this method is not intended to be called directly by code in your Generator or Script code, where you would normally call Render or RenderToFile. You would only call TransformText (and now Transform) method in unit testing code to validate code generation results without creating the output files. If you have any code that calls the now abstract TransformText method, change it to call the new Transform instead.

Introducing this breaking change was not an easy decision. It was necessary to “unseal” implementation of the TransformText in order to make T4 Toolbox compatible with TextTemplatingFilePreprocessor in Visual Studio 2010 which assumes that this method is abstract. Although it would have been possible to keep backward compatibility, it would result in confusing design and implementations working differently in traditional and preprocessed templates. Taking into consideration the effort required to maintain this going forward, we made a decision to go ahead and convert existing templates now and leave this change behind.

The changes required to upgrade existing code are straightforward. You can use the “Find in Files” feature in Visual Studio to find all instances of RenderCore methods that need to be converted to TransformText. This is a manual change as it requires you to add a return statement at the end of each method. Replacing calls to TransformText method with Transform can be safely accomplished using the “Find and Replace” across multiple files. Including code changes, running unit tests and resolving errors, this change took less than an hour with the existing code generators in T4 toolbox itself.

Under the Hood

In order to make T4 Toolbox compatible with both Visual Studio 2008 and Visual Studio 2010, we now have to separate assemblies: T4Toolbox.dll, a .NET 3.5 assembly which is used in Visual Studio 2008, and T4Toolbox.10.0.dll, a .NET 4.0 assembly which is used in Visual Studio 2010. Introducing a separate new binary was required because Microsoft.VisualStudio.TextTemplating assembly in Visual Studio 2010 has been renamed to Microsoft.VisualStudio.TextTemplating.10.0, which means that TextTransformation base class in Visual Studio 2010 is now physically different than the same class in Visual Studio 2008, forcing you to have separate binaries for descendants.

Producing a .NET 4.0 version of the T4Toolbox assembly required a complete overhaul of the build system. The project files had to be upgraded to Visual Studio 2010. To keep complexity under control and have a single set of project files, they had to be hacked to generate an assembly with different target .NET framework versions depending on build configuration. This had to be done directly in the project files because target framework is exposed as a project-level setting by Visual Studio 2010.

Microsoft SDC tasks don’t appear to support MSBuild 4.0 at this time and generation of Visual Studio project item templates had to be changed to use MSBuild extensions in the DSL SDK.

Because of these changes, the previously published instructions on how to get and compile T4 Toolbox source code are now incorrect. I will not go back and update these instructions until we have a release version of Visual Studio 2010 and things settle down a bit.


Write a Comment

Take a moment to comment and tell us what you think. Some basic HTML is allowed for formatting.

Reader Comments

tangible T4 Editor for VS 2010 Beta 1 and later…
Just in case someone might be wondering - yes there is a tangible T4 Editor for VS2010 Beta. Please make sure you follow the steps here to install it. It is found in the VS Extension Manager.
Make sure that if you run VS as Admin or under XP that you do set the following checkboxes in the Tools->Options plus “Load Extensions from my local applications folder” – if you run VS as Admin.

More infos here:
http://tangibleengineering.blogspot.com/2009/05/tangible-t4-editor-now-listed-in-visual.html

[…] T4 Toolbox: Support for Visual Studio 2010 (Oleg Sych) […]

Good morning. I trying to use T4 toolbox to generate code for Linq. Is there some way to update dbml file without designer (removing and dragging-dropping)? I tryed to use SqlMetal to do this, but dbml it provided is unsuitable for T4 toolbox templates.

[…] T4Toolbox Library that simplifies developent of T4 code generation templates. T4Toolbox: http://t4toolbox.codeplex.com/ Oleg Sych’s blog (has many T4 Tutorials):http://www.olegsych.com/2009/10/t4-toolbox-support-for-visual-studio-2010/ […]

Runing Visual Studio 2010 on x64 XP
“The type or namespace name ‘T4Toolbox’ could not be found (are you missing a using directive or an assembly reference?)” Do I need to reference the toolbox dll? Where can I find it?

Yes, you need a reference. The assembly can be found in the global Assembly Cache and %ProgramFiles%\T4 Toolbox\Bin.

When I got latest code from codeplex, I built the anycpu assembly and re-pakcaged, I am not sure the reason that when I re-ran the tt template, throw the following excetpion:
Error 18 Running transformation: System.TypeLoadException: Could not load type ‘Microsoft.VisualStudio.TextTemplating.Interfaces.ITextTemplatingEngineHost’ from assembly ‘Microsoft.VisualStudio.TextTemplating.Interfaces.10.0, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’.
at T4Toolbox.TransformationContext.Render(String content, OutputInfo output, CompilerErrorCollection errors)
at T4Toolbox.Template.Render()
at NCS.IConnect.Core.CodeGeneration.CodeGenerator.RunCore() in C:\Project\iConnect\iConnect\iConnect\SourceCode\Core\CodeGeneration\CodeGenerator.cs:line 76
at T4Toolbox.Generator.Run()
at Microsoft.VisualStudio.TextTemplatingF75D15B16AD9C227E429E4B5CF06426E.GeneratedTextTransformation.TransformText() in MESSAGES.tt:line 11
at Microsoft.VisualStudio.TextTemplating.TransformationRunner.RunTransformation(TemplateProcessingSession session, String source, ITextTemplatingEngineHost host, String& result) 1 1

Hi Oleg,

I want to create a Visual Studio Item Template that generates an Item (for eg. custom .aspx page) in the solution by executing T4 Template while adding it to the solution.
I read the following post : http://stackoverflow.com/questions/805979/t4-templates-and-visual-studio-item-templates

Is it possible to implement this without using GAX. I mean is it possible to start by using a standard project item template and T4 Templates only, which doesn’t require GAX.

I’m wondering if it’s possible to called a preprocessed generator from a TT script? I can’t seem to find a syntax that the TT engine likes. Ordinarily I can include a generator with , but a preprocessed generator is defined in a regular CS file. I can’t find a way of importing the namespace it’s in to make the preprocessed generator “visible” to my script. Any thoughts?

Gah.. comment munched by HTML filter…

I was trying to say that with a generator defined in a TT file, I can ordinarily use
(#@ include “generator.tt” #) to access it in another TT script, but that doesn’t work with preprocessed generators that are defined in a regular CS file.

Hi,
I am new to T4. I have installed T4 Toolbox in VS2012. and created a simple template and changed the custom tool property to ‘TextTemplatingFilePreprocessor’.

It is throwing the error Error “‘testTemplate.test.Dispose(bool)’: no suitable method found to override”

It would be helpful if it can be resolved.

Thanks in advance