Caching in latest T4 drop

Adam Miller has been using our T4 engine and has a question about caching...

A caching question: Using the standard templating engine (Microsoft.VisualStudio.TextTemplating.Engine),  is there a way to cache the same template file between generations? Specifically, the engine.ProcessTemplate seems to recompile the template each time. Is there a way to cache it? It's taking us minutes to generate 200-300 templates all based on a single template file with  different arguments being passed to it.

The code is as easy as: engine.ProcessTemplate(contentStr, new TemplateHost(".", templateArgs).

In our latest CTP, we've implemented a basic caching scheme which not only speeds up generation from DSL models with Visual Studio, but allows you to speed up your own Visual Studio extensibility projects that take advantage of the T4 engine.

We've implemented a caching scheme based on the full content of the template, including all files included with an <#@ include #> directive and, critically, all of the code injected by any directive processors.  If that set of pieces catenated as a string hashes the same then we'll attempt to reuse the compiled transformation class from a previous run.  We're using a 128-bit MD5 hash right now.  If anyone has any collision problems with that bit depth, I'd like to hear from them.

The cache is cooperative between the T4 engine and its host.  To turn on the caching features, you'll need to implement the following new method in the hosting API as follows:

public object GetHostOption(string optionName)

If optionName is "CacheAssemblies" and you return boolean true, then the engine will reuse generated transformation code rather than compiling it every time.  If you simply return null on this call, the previous non-caching behavior will be preserved.

Obviously, as with any hashing-only solution, your host should provide an end-user toggleable switch to turn off the cache just in case someone is unlucky enough to hit a collision.
In the DSL Tools' VS-hosted T4 implementation, the switch to turn off caching is in the registry.  If you add a string value CacheAssemblies="false" to the key


then you'll turn off caching.

Adam, I hope this new feature meets your requirements.  I'd be especially interested to know if your argument-passing scheme works with this implementation or defeats it.  Please do let me know how you get on with it.

Don't forget, our latest CTP is also the first public bow for the changes George mentioned some time ago around features to make building up libraries of code generation templates much easier.

Comments (7)
  1. amiller12 says:

    I’ve been using the TemplateHost class located in the Microsoft.Practices.RecipeFramework.VisualStudio.Library.Templates library. In addition, I’m using my own templates, etc. instead of any of the DSL stuff. When looking at the TemplateHost class, it doesn’t contain the new GetHostOption method noted above. I’m worried that this means I need to write my own TemplateHost class, (and started with the example under the ITextTemplatingEngineHost Interface section of the SDK, but I feel like I’m reinventing the wheel.) I could probably subclass also and just add the necessary method above but again – I feel like I’m missing something. Any suggestions on where to go from here?

  2. GarethJones says:

    Hi Adam,

    The current GAT/GAX works with the previous T4 drops (

    The new T4 drop is version and won’t work with GAT/GAX until those guys release a version that implements the breaking changes to the interface.

    As you say, you’ll need to implement your own host class.  Hopefully that’s not too onerous a task.

  3. amiller12 says:

    Everything seems pretty straightforward except for the implementation of the template arguments. In the GAT layer, they pass in their own Dictionary of PropertyData (their own definition). Behind the scenes, can you shed some light on how to best implement that piece with the methods as defined in the ITextTemplatingEngineHost Interface? The only example code I’ve been able to find has been in the SDK about this interface at all.

  4. GarethJones says:

    I don’t have a copy of GAT on a handy machine right now, but IIRC, GAT uses some sort of AppDomain-relative storage for those parameters, then has a custom directive processor which generates code to retrieve them on the fly at template run-time.

    Your host class could likewise store its data at a well known location.  ALternatiely, you can make your templates specific to your host by turning on HostSpecific=true in the <#@ template #> directive.

    This will cause your template to have access to a Host property which will retrieve your host at template run time (assuming your AppDomain/Marshalling allow it).

    You can then cast this to any interface that your host object happens to support.

  5. amiller12 says:

    I’m using all of the latest June/July drops and it doesn’t look like caching is now working. What’s the best way to see if it’s working properly? I’ve reduced the code down to a simple T4 file that contains basically nothing and just call converting it 50 times in a loop. It still takes it about 15 seconds to do this. Seems like it should convert it once and then be very fast.

    I’m specifically using the TemplateHost that comes out of the box with the GAT/GAX.

    Simplified code:

    string content = File.ReadAllText(fullTemplateFileName);

    for(int i=0;i<50;i++)


    IDictionary<string, PropertyData> templateArgs = new Dictionary<string, PropertyData>();

    TemplateHost host = new TemplateHost(".", templateArgs);

    host.TemplateFile = fullTemplateFileName;

    string result = engine.ProcessTemplate(content, host);


  6. GarethJones says:

    Hi amiller12

    Caching is a handshake between the engine and its host and I don’t believe the GAT/GAX folks enabled it.

  7. VS2010学习 says:

    Mike Pagel recently posted an interesting article about T4 on CodeProject called &#8220; T4: Extending

Comments are closed.

Skip to main content