Death to T4 Text Templates: R4MVC5

Yes, I know 'T4 text template' is technically redundant, but without 'text template,' 'T4' is basically un-Google-able.

At my work, we use ASP.NET MVC 5. With it, we use what I suspect is the most common T4 template: T4MVC. While this fancy template solves a lot of problems, it turned into a very large one for our team.

We have a lot of changes occurring and a lot more feature requests in our backlog. Originally, the files that T4MVC was generating were tracked in version control. As you can imagine, the generated files were a constant source of conflicts in a moderately-size team that made a massive amount of changes.

I wanted to ignore generated files. It took a while to get everyone on board, but we finally stopped tracking all the generated and merge conflicts became a less-frequent occurrence. Rejoice! (This was one of my demands when I instigated the change in how we use Git.)

There was one issue, though. While we could ignore CSS and JS files, and regenerate them easily, we found that we couldn't get T4MVC to run outside of Visual Studio. This means that we'd have to re-generate the files while in Visual Studio. This wasn't too much of a problem, since there are extensions for regenerating T4 templates.

In addition to ignoring generated files, I suggested that we use Pull Requests (believe it or not, we weren't using them!). This suggestion was initially not taken and developers manually merged their changes into the integration branch prior to code-review, but I saw it as a temporary compromise.

I reformulated and figured I'd just nudge everyone into using them when I could. I set up all of my branches that others had to collaborate on as protected and required devs that worked off of them to create PRs. I used them in other circumstances as well, and would make hints on how they make code-review easier for those that don't want to diff from the command-line. I think it worked, because the decision to start using PRs was made.

As we were planning how we'd get everyone to use PRs, I pushed for branch policies, automated builds, and build verification before merging. We then researched how we'd actually do it. We soon ran into the T4MVC issue again, this time finding the exact reason why it only worked inside VS.

Now the decision to use automated builds has been made, but the T4MVC issue still exists. While the decision to go back to tracking the generated files and foregoing build-verification was made, this wouldn't do for me, and I looked into ways to generate the helper classes of T4MVC outside of Visual Studio.

There are a lot of abandoned attempts I made: forking SharpDevelop and using their DTE with (there is a neglected fork out there — couldn't escape a circular dependency issue due to how the Host behaved), a complete re-implementation using Scripty (Scripty is too broken), implementing a hacky version of Scripty using Buildalyzer (ran into strange dependency errors) to try to more-or-less follow the previous approach, implement a hacky version of Buildalyzer using the MSBuild APIs so I could implement a hackier version of Scripty) because it was a much smaller project than the other starting points (and easy to follow/experiment with).

With great Googling, I eventually found T4MVCCoreLite and looked through the commits and found that the code came from the R4MVC project. I down-ported it to ASP.NET MVC 5 using what I learned in the abandoned attempts, got some code generated, and then took the latest R4MVC tip and did it all over again. (We couldn't just use plain R4MVC since it's for ASP.NET Core MVC.)

It worked!

Here's the repo!

Prev  Hell, World!