How to Run T4MVC on Build

T4MVC is a very nifty little T4 template that generates some strongly typed helpers, to avoid fiddling with strings when referring to controllers, actions and views.

Its build using EnvDTE these days, so you don’t have to build your solution before running the template, which is nice.

There is however one slight little thing, that would make the experience complete: If it would run before build, so its always updated and we thereby avoid build errors due to errors in generated code.

Out of the box, this is nearly working due to the setting AlwaysKeepTemplateDirty, that sets the saved boolean to false, forcing the template to run. But this only works if the template has run once.

So when you open Visual Studio and change a MVC controller, you have the problem.

The only way i could figure out how to do this, was to use EnvDTE and add an eventhandler to the BuildEvents.OnBuildBegin event.

You push ALT+F11 to get to the Macro IDE, click EnvironmenEvents and add the eventhandler in the below code snippet . Make sure that its added outside the autogenerated code section.

Public Sub OnBuildBegin(ByVal Scope As EnvDTE.vsBuildScope, _
                        ByVal Action As EnvDTE.vsBuildAction) _
                        Handles BuildEvents.OnBuildBegin
 
    If Scope = vsBuildScope.vsBuildScopeSolution _
        Or Scope = vsBuildScope.vsBuildScopeProject Then
 
        Dim projectItem As ProjectItem _
            = DTE.Solution.FindProjectItem("T4MVC.tt")
 
        If Not projectItem Is Nothing Then
            If Not projectItem.IsOpen Then
                projectItem.Open()
            End If
            projectItem.Save()
        End If
 
    End If
End Sub

***UPDATE***: Encouraged by the comment by David Ebbo, I have modified the code a little so that it runs the custom tool directly instead of opening and saving the file. This is cleaner, but you have to reference the VSLangProj.dll, to use the VSProjectItem.

Public Sub OnBuildBegin(ByVal Scope As EnvDTE.vsBuildScope, _
                ByVal Action As EnvDTE.vsBuildAction) _
                Handles BuildEvents.OnBuildBegin
 
    If Scope = vsBuildScope.vsBuildScopeSolution _
        Or Scope = vsBuildScope.vsBuildScopeProject Then
 
        Dim projectItem As VSProjectItem _
            = DTE.Solution.FindProjectItem("T4MVC.tt").Object
 
        If Not projectItem Is Nothing Then
            projectItem.RunCustomTool()
        End If
 
    End If
End Sub

This obviously isn’t the perfect solution, as it is run for all solutions or projects that you build – not just MVC ones. But if you keep it while you primarily work on MVC projects with T4MVC, and then comment it out when not, you’ll be fine.

This could also be wrapped up in an Addin, so that you could turn it on and off via the Addin menu.

Remember to change the filename if you are using Rory Beckers VB version T4MVCVB.tt

Resources:

Posted March 11, 2010 by Joachim Lykke Andersen
In

Comments [8]   
Friday, March 12, 2010 8:09:56 PM (Romance Standard Time, UTC+01:00)
Thanks for blogging this! I'll right a post as well and point to here :)

I wonder, instead if opening and saving the file, if it would be possible to just run the custom tool on it. i.e. do the equivalent of right clicking on the .tt file and choosing "Run Custom Tool". Not sure how to do this, but presumably that's possible.

Oh, and an Addin would be cool too if you ever get a chance :)
Friday, March 12, 2010 8:24:37 PM (Romance Standard Time, UTC+01:00)
Ok, I just blogged it: http://blogs.msdn.com/davidebb/archive/2010/03/12/a-better-way-to-auto-run-t4mvc-when-you-build.aspx
Friday, March 12, 2010 8:38:21 PM (Romance Standard Time, UTC+01:00)
Thanks. I will look into running custom tool instead of saving the document. In regards to an Addin, I will put one up shortly :)
Friday, March 12, 2010 9:08:12 PM (Romance Standard Time, UTC+01:00)
I have added some modified code to the post, that runs the custom tool directly instead of opening and saving the file. But not that you need to reference VsLangProj.dll for it to work.
Friday, March 12, 2010 9:39:15 PM (Romance Standard Time, UTC+01:00)
Thanks, RunCustomTool() is a nice improvement. When you say you need to import VsLangProj.dll, you just mean adding 'Imports VSLangProj' at the top of the EnvironmentEvents files, and not having to import the DLL in the each MVC project, right? If so, it's a painless one-time thing :)

Minor comment: when I copy your code above and paste it in VS, it loses newlines and ends up all on one big line. Maybe some HTML formatting thing?
Friday, March 12, 2010 9:47:24 PM (Romance Standard Time, UTC+01:00)
You add the .dll reference once in the Macro project and the import statement, and thats it - when you load a brand new project, you don't have to do anything. So yes, its a one-time thing.

About the formatting, apparently all browsers give a different result. I tested it in Chrome, and it works nicely. But from IE i get one line, and in Firefox i get extra lines.

I will have a go at fixing it.
Friday, March 12, 2010 10:53:47 PM (Romance Standard Time, UTC+01:00)
I have switched to SyntaxHighlighter for the code. This has helped a great deal, but in IE I still get extra linefeed. But its definitely better, and in Firefox and Chrome it pastes nicely. Hope its ok, otherwise please let me know.
Saturday, March 13, 2010 3:50:40 AM (Romance Standard Time, UTC+01:00)
Yes, it has extra line feeds, but that's still better than everything in one line. Let's call that good enough! :)

FYI, this is what I use: http://www.hanselman.com/blog/BestCodeSyntaxHighlighterForSnippetsInYourBlog.aspx. It's nice because all the highlighting is done client side.
All comments require the approval of the site owner before being displayed.
OpenID
Please login with either your OpenID above, or your details below.
Name
E-mail
(will show your gravatar icon)
Home page

Comment (HTML not allowed)  

Enter the code shown (prevents robots):

Live Comment Preview