Udostępnij za pośrednictwem


What’s new in T4 for Visual Studio 2013?

Visual Studio 2013 Preview has been out for a while now so I thought I should announce the new goodies in the product for T4 this time around. As the T4 engine is fairly mature now we focused on a couple of scenarios that have been blocked or tricky for customers. I’m sure you’ll agree they are good ones.

1. Enable fine-grained template reuse with a new ‘once’ option on the <#@ include #> directive.

This feature makes it really easy to build up a library of reusable T4 snippets that you can include at will without worrying that some other snippet has already included them.  For example, I’ve now got a library of very fine-grained snippets that deal with template processing and C# generation.  In turn, these are used by some more task-specific utilities such as generating exceptions, which I can then use from any more application-specific template.  You can see in this dependency graph that my indentation helpers are used all over the place.  Now I don’t have to worry about clashes.

Dependencies between template snippets.

Customers ask me a lot about strategies for building reusable template libraries and the ‘once’ feature is the last major unblocker to a smooth experience for big libraries.  This feature works regardless of the host in use.  Here’s the syntax:

<#@ include file=“myinterestingsnippet.t4” once=”true” #>

2. Enable project-relative assembly references and includes across IDE and msbuild.

Until now, it’s been awkward to create templates that reference assemblies from standard project-relative directories and then transform them in both the IDE and from msbuild.  Typically it required environment variables, which most people hate!  We’ve fixed that with this feature.  You can now use project properties with include and assembly directives.  This feature works in the standard IDE host and in the msbuild host.  Here’s an example – imagine we have some helper code in an assembly called myLib.dll stored in a standard ‘libs’ directory.  Something magnificent, like this:

 namespace MyLib
 {
     public static class MyClass
     {
         public static string MyMethod()
         {
             return "World";
         }
     }
 }

 

Now let’s use that helper from a template – in the IDE we could use macros like $(SolutionDir), but those don’t work in msbuild, so we’ll use a project variable instead:

 <#@ template debug="false" hostspecific="false" language="C#" #>
 <#@ assembly name="$(libDir)\MyLib.dll" #>
 <#@ output extension=".txt" #>
 Hello <#= MyLib.MyClass.MyMethod() #>

Of course, we’ll need to define the variable in our project file by adding a snippet like this:

 <PropertyGroup>
     <libDir>$(MSBuildProjectDirectory)\..\libs</libDir>
 </PropertyGroup>

 

At this point, the template should work in the IDE, but we need to take one more step before it works in msbuild.  We need to let the T4 msbuild task know which variables we’re using.  We add one final snippet to do that:  

   <ItemGroup>
     <T4ParameterValues Include="libDir">
       <Value>$(libDir)</Value>
     </T4ParameterValues>
   </ItemGroup>

 

3. Standard host used in ASP.Net scaffolding

This isn’t strictly a T4 feature, but it’s great news.  The very cool new ASP.Net scaffolding feature uses the standard VS T4 host, so you can use the full power of T4, and any include libraries you have when building scaffolding templates.

 

4. Tidy up after very spendy templates with CleanupBehavior directive.

Sometimes templates get big.  Or crufty. Or both. Or they load a bajillion assemblies to do their work.  This can bloat up your IDE’s memory footprint or lock assemblies in memory.  Now there’s a great big hammer to solve this problem.  Add the following line to your template and the appdomain it runs in will get blown away after every run. 

 <#@ CleanupBehavior processor="T4VSHost" CleanupAfterProcessingtemplate="true" #>

This defeat’s T4’s normal caching behavior, so it slows things down a bit, but you get a spangly clean IDE every time.  This one only runs in the VS IDE host.

 

5. A bunch of small bugs, but that goes without saying.

Enjoy the release.

Comments

  • Anonymous
    August 29, 2013
    Still no first class editor support!! This is disappointing...

  • Anonymous
    September 09, 2013
    Hi Gareth, thank you for posting we will make sure the new features are well supported by our tangible T4 Editor. Tim

  • Anonymous
    November 12, 2013
    Why can't Microsoft create a usable editor that is integrated into their products.  Having to pay extra for a 3rd party addin for what are standard features in C#, VB, etc, but not T4 is disappointing.

  • Anonymous
    November 19, 2013
    I have a folder structure something like this: TestsGenerated Codetest_foo1.tt TestsGenerated CodeIncludetest_shared1.ttinclude SrcGenerated Codesrc_foo2.tt Generated CodeIncludesrc_shared2.ttinclude test_foo1.tt: <#@ include file="Includetest_shared1.ttinclude" once="true" #> <#@ include file="......SrcGenerated CodeIncludesrc_shared2.ttinclude" once="true" #> src_foo2.tt: <#@ include file="Includesrc_shared2.ttinclude" once="true" #> src_foo2.tt works fine, but test_foo1.tt gets an error that definitions in src_shared2.ttinclude are already defined, and as far as I understand that is because once="true" did not do its job. If I move all templates into the same folder it seems to work.

  • Anonymous
    November 19, 2013
    I have a folder structure something like this: TestsGenerated Codetest_foo1.tt TestsGenerated CodeIncludetest_shared1.ttinclude SrcGenerated Codesrc_foo2.tt Generated CodeIncludesrc_shared2.ttinclude test_foo1.tt: <#@ include file="Includetest_shared1.ttinclude" once="true" #> <#@ include file="......SrcGenerated CodeIncludesrc_shared2.ttinclude" once="true" #> src_foo2.tt: <#@ include file="Includesrc_shared2.ttinclude" once="true" #> src_foo2.tt works fine, but test_foo1.tt gets an error that definitions in src_shared2.ttinclude are already defined, and as far as I understand that is because once="true" did not do its job. If I move all templates into the same folder it seems to work. P.S: Please delete duplicate anonymous post.

  • Anonymous
    December 08, 2013
    Great! Have you fixed the following bug? The Debug T4 Feature in VS2012 does not expand the $(SolutionDir) variable connect.microsoft.com/.../the-debug-t4-feature-in-vs2012-does-not-expand-the-solutiondir-variable Evan

  • Anonymous
    March 24, 2014
    Why would anyone use this tool for anything serious?  Visual Studio won't even run the templates at build time.  What good is it if you can't rely on the compilation to be consistently updated without having to manually run stuff all the time?  A little more effort would have made this is very useful tool.  What a waste.

  • Anonymous
    April 24, 2014
    Hi, @ Andreas Larsen - just to let you know I have logged a bug for the once="true" problem and the team is looking into it. Thank you for the detailed repro steps! @ Not fooled - you can integrate the transformation process at build time. This is documented on msdn under the title "Code Generation in a Build Process" - msdn.microsoft.com/.../ee847423.aspx. There are also community nuget packages that do this with the help of the standalone TextTransform.exe tool. Still, based on user feedback we recognize that the process is cumbersome and we are reviewing ways of simplifying it. @Evan - the bug appears to have been fixed.

  • Anonymous
    May 08, 2014
    It would be really nice if T4 can be "told" to NOT generate a file if said file already exists. Some projects require multiple T4 files to generate the various parts and some of those generations are very long but only need to be done either once or once is a great while because what they are generating doesn't change much. To include a property like <@# output overwriteOutput="false" #> would be really great. I believe this feature is in the T4Toolbox (which I don't use because of the long delay in upgrade from VS versions) so it would be nice to have it "native".

  • Anonymous
    September 28, 2014
    The comment has been removed