T4MVC 2.5.00 update: multiple output files and minified javascript support

To get the latest build of T4MVC:

Go to T4MVC page on CodePlex

T4MVC build 2.5.00 brings a couple of fun new features that I’ll describe in this post.  I can’t take too much credit for them as they came from users who suggested them to me, and helped out getting the code going.

Support for multiple output files

Up until now, T4MVC.tt has always generated a single file, which is the T4MVC.cs that you see get nested under it in VS.  And normally, this is the way T4 templates work: they just generate one file.  But last week I got an email from Stuart Leeks who pointed me to a new blog post from Damien Guard that describes a nice way to get around this limitation.  All of Damien’s logic is very nicely encapsulated in a class, making it pretty easy to add to an existing T4 template without having to make significant changes.

I was going to look into getting that in T4MVC, but Stuart went ahead and did it, so I didn’t have much to do myself.  Thanks to Stuart and Damien on this one!

But first I suppose we should discuss why generating multiple files is a good thing.  Quite simply, it keeps things more organized, and makes things cleaner when working with source control.  Since T4MVC can generate a fair bit of code, it is a good candidate to use this.  Specifically, T4MVC can now generate a different output file for each controller, making things more manageable.  Note that it still generated the ‘primary’ T4MVC.cs file, which contains all the top level things that don’t belong to any specific controller.

This behavior is on by default, but can be disabled in T4MVC.settings.t4:

// If true,the template output will be split into multiple files.
bool SplitIntoMultipleFiles = true;

I debated whether to make it the default, but in the end opted for it, as I didn’t see any serious drawbacks.  But I guess if you never plan to look at or deal with the generated files in any way, it doesn’t buy you a whole lot and you may choose to turn it off.

Warning if you’re using VS2010 Beta 2: Damien’s code uses the ITextTemplatingEngineHost interface, which got moved to a new Microsoft.VisualStudio.TextTemplating.Interfaces namespace in 2010 Beta 2.  So on 2010 Beta 2, you’ll need to add one extra import line to T4MVC.tt (the second line below):

<#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
<#@ import namespace="Microsoft.VisualStudio.TextTemplating.Interfaces" #>

Support for Minified Javascript files

This one came from Matt Wicks.  Minified javascript files are alternate version of the files that makes them as small as possible, but using various strategies like removing white space.  e.g. in an MVC application’s Scripts folder, you’ll typically see both jquery-1.3.2.js and jquery-1.3.2.min.js.  Usually, you want to use the minified version at deployment time (to make your site load faster), but the regular version at development time, so you can more easily debug into it.

The new T4MVC support makes it automatic to use one vs. the other depending on the context.  T4MVC has been supporting script files for a while, letting you write:

<script src="<%= Links.Scripts.jquery_1_2_6_js %>" type="text/javascript"></script>

With this new feature, you don’t need to change anything to this line, but the token jquery_1_2_6_js will automatically point to either jquery-1.3.2.js or jquery-1.3.2.min.js depending on whether you’re running in production.  How does it know whether you’re in production?  It calls a method defined in T4MVC.settings.t4 which makes the decision.  By default, it looks at whether debugging is enabled:

    // Logic to determine if the app is running in production or dev environment
public static bool IsProduction() {
return (HttpContext.Current != null && !HttpContext.Current.IsDebuggingEnabled);
But you can easily change this logic if you have a different way of determining ‘production’.

Comments (9)
  1. Have you tried this in a v1 Vs2008 MVC project?

    This is the error I get:

    Error 26 Running transformation: System.InvalidCastException: Specified cast is not valid.

      at EnvDTE.Document.set_Saved(Boolean pRetval)

      at GetProjectContainingT4File(DTE dte) in (Project)T4MVC.tt:line 360

      at PrepareDataToRender(TextTransformation tt) in (Project)T4MVC.tt:line 318

      at TransformText() in (Project)T4MVC.tt:line 36

    (stripped mostly unnecessary stuff like my project location or the generated namespaces)

    My workaround was pretty simple: comment the line out. Unfortunately that means generating the template every time as I don’t get that cool "Hey I’m not really saved yet" hack.

    As to why it all of a sudden broke? No clue. From what I was looking at it shouldn’t have.

  2. David Ebbo says:

    @Jeremy: strange, I’m not seeing this. When you say VS2008, do you mean VS2008 SP1?  That’s what I’m trying with.

    A couple of things to try:

    – Do you see this with a brand new MVC project?

    – Does it all work if you go back to the previous version?

    Let’s take it offline to investigate.

  3. Dan Atkinson says:

    I am also getting an error:

    Error Running transformation: System.NullReferenceException: Object reference not set to an instance of an object.

      at Microsoft.VisualStudio.TextTemplating0510DCEADB122D738D7214814B6A89EC.GeneratedTextTransformation.FunctionInfo..ctor(CodeFunction2 method) in line 811

      at Microsoft.VisualStudio.TextTemplating0510DCEADB122D738D7214814B6A89EC.GeneratedTextTransformation.ResultTypeInfo..ctor(CodeType codeType) in line 902

      at Microsoft.VisualStudio.TextTemplating0510DCEADB122D738D7214814B6A89EC.GeneratedTextTransformation.ProcessControllerActionMethods(ControllerInfo controllerInfo, CodeClass2 current) in line 477

      at Microsoft.VisualStudio.TextTemplating0510DCEADB122D738D7214814B6A89EC.GeneratedTextTransformation.ProcessControllerTypesInNamespace(CodeNamespace ns) in line 432

      at Microsoft.VisualStudio.TextTemplating0510DCEADB122D738D7214814B6A89EC.GeneratedTextTransformation.ProcessControllersRecursive(ProjectItem projectItem) in line 385

      at Microsoft.VisualStudio.TextTemplating0510DCEADB122D738D7214814B6A89EC.GeneratedTextTransformation.ProcessControllersRecursive(ProjectItem projectItem) in line 379

      at Microsoft.VisualStudio.TextTemplating0510DCEADB122D738D7214814B6A89EC.GeneratedTextTransformation.ProcessControllersFolder(Project project) in line 372

      at Microsoft.VisualStudio.TextTemplating0510DCEADB122D738D7214814B6A89EC.GeneratedTextTransformation.PrepareDataToRender(TextTransformation tt) in line 330

      at Microsoft.VisualStudio.TextTemplating0510DCEADB122D738D7214814B6A89EC.GeneratedTextTransformation.TransformText() in line 36

  4. David Ebbo says:

    @Dan: could you contact me by email to discuss this?  This seems different from what Jeremy is hitting (which we’re still investigating).

    Was T4MVC working for you in the previous build?

  5. Dan Atkinson says:

    @david: I can’t find an old version to try out and went straight to 2.5.00.

    I’ll send you an email as soon as possible.


  6. David Ebbo says:

    @Dan: I have a possible fix for you to try.  Please email me at david.ebbo AT microsoft.

  7. David Ebbo says:

    @Dan: I have pushed build 2.5.01 to CodePlex, which should address this NullRef issue. It happened when you use a custom ActionResult type without a ctor, but the new drop should handle that. Jeremy’s issue is distinct, and still unsolved, as he stopped being able to repro it himself.

  8. Andrew Gunn says:

    I can reproduce the "Specified cast is not valid exception". It worked fine when I added the files to the project but threw the exception after I edited the .tt file to change some interfaces/namespaces.

    My fix was to copy the files to another location, remove them VS and add them again – a bit of a pain. I’m using VS2008 SP1.

  9. David Ebbo says:

    @Andrew: I moved this investigation to the new forum: http://forums.asp.net/t/1497300.aspx.

    Can you follow up on there to help getting to the bottom of it?


Comments are closed.

Skip to main content