Scott Hanselman

T4MVC and R4MVC - Roslyn code generators for ASP.NET Core tag helpers

September 07, 2017 Comment on this post [10] Posted in ASP.NET MVC | Open Source
Sponsored By

I've always loved the T4 text generator within Visual Studio. If you are looking for T4 within Visual Studio 2017 you need to install the "Visual Studio extension development" option within the installer to access it. However, T4 development seems stalled/done and if you want to utilize some of it.

There's a nice open source project called T4MVC that you can use with Visual Studio 2015 and ASP.NET MVC to create strongly typed helpers that eliminate the use of literal strings in many places. That means instead of:

@Html.ActionLink("Dinner Details", "Details", "Dinners", new { id = Model.DinnerID }, null)

T4MVC lets you write

@Html.ActionLink("Dinner Details", MVC.Dinners.Details(Model.DinnerID))

Fast forward to 2017 and that team is working on a new project called R4MVC...it's a code generator that's based on Roslyn, the .NET Compiler Platform (hence the R).

It also lets you update your @Html.ActionLinks to be strongly typed, but more importantly it lets you extend that to strongly typed taghelpers, so instead of:

<a asp-action="Details" asp-controller="Dinners" asp-route-id="@Model.DinnerID">Dinner Details</a>

you can write

<a mvc-action="MVC.Dinners.Details(Model.DinnerID)">Dinner Details</a>

It's generating the URL for that <a> tag using the method and parameter.

Using an ASP.NET Core 1.1 app (2.0 is coming soon they say) I'll add the NuGet packages R4Mvc.Tools and R4Mvc, making sure to "include prerelease."

Adding R4Mvc.Tools in NuGet

I'll run "Generate-R4MVC" in the Package Manager Console.

Generate-R4MVC

There is a new R4Mvc.generated.cs file that gets created, and inside it is a whole bunch of classes based on the files on disk. For example I can type @Links.css, or @Links.lib and start getting intellisense for all my files on disk like JavaScript or CSS.

Links.css

When returning a view, rather than return View("About") I can do return View(Views.About):

return View(Views.About)

The R4MVC project also has Tag Helpers so their mvc-action attribute gives you strong typing like this:

<a mvc-action="MVC.Home.Index()">

This R4MVC project is just getting started, but I'm sure they'd appreciate your support! Head over to https://github.com/T4MVC/R4MVC/issues and learn about what they are planning and perhaps help out!

What do you think? Do you think there's value in smarter or strongly-typed URL generation with ASP.NET?


Sponsor: Raygun provides real time .NET error monitoring and supports all other major programming languages and frameworks too! Forget logs and support tickets. Reproduce software bugs in minutes with Raygun's error tracking software!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service
September 07, 2017 23:21
Finally.

Magic strings are always a smell, and til now there was no decent way around it.

T4MVC was a pioneering project in that regard; it had some quirks and I never understood why Microsoft is not embracing it as a proper tooling feature of Visual Studio.
September 08, 2017 0:44
Thanks for the nice review Scott !
I wanted to say that it already supports aspnetcore 2.0 !
September 08, 2017 1:18
I also cannot comprehend why Microsoft doesn't promote/develop T4 further. It is an essential compliment to development in C#. Yet most developers have never even heard of it because its hidden in Visual Studio and the tooling for it hasn't been updated in 10 years.

It shouldn't require 3rd party extensions to get syntax highlighting with T4. VS 2017 should not ship with T4 debugging broken (https://stackoverflow.com/questions/43184337/cannot-debugging-t4-template-in-vs2017)

And yet for developers who have used it, T4 is extremely popular. This issue asking for better tooling had over 3,000 votes before it was tragically closed (https://visualstudio.uservoice.com/forums/121579-visual-studio-2015/suggestions/3793790-t4-editing).
Sam
September 08, 2017 4:15
Finally, We can get rid of the magic string. Good open source.
September 08, 2017 10:12
I also agree, that T4 is useful tool in C# developer's belt and I think there were two reasons, why it didn't get much traction are:
1) writing T4 code in Visual Studio without extensions is painful, third party extensions weren't stable (I've used ForTea extensions for R# (extension for extension :))
2) CodeDOM API was slow and hard to use, you could get away sometimes with reflection - but that had its own drawbacks (somewhat slow also, you needed to compile before transforming template and if template was generating C# code it was even more complicated ;)

So it became a closed loop - there's no critical mass in developer community to push Microsoft invest in T4 and there's no investments in T4 because there's no critical mass.
September 08, 2017 14:30
I believe the correct the approach for these kind of problems is either to use something like F#'s type providers or Nemerle's lisp style macros. Too bad c# doesn't support either. Generated code is still the code you have to maintain, and can be problematic on source control while merging.
September 08, 2017 21:07
Nice idea but when you are using Resharper seems quite useless. Resharper is able to analyze ASP.NET project and provide intellisense as well as static analysis for parameters which accept view's, controller's and actions's names.

Regarding Link TagHelper - providing controller's name, action's name and action's parameters as a separated attributes is very inconvenient and hard to maintain. It should be used with some helper with accepts Expression<Action<T>> as main parameter, something like that
<ns:a href="Link<HomeController>.ForAction(c=>c.Home(param))" text="Home" />

If you have Expression<Action<T>> you can extract from it many useful information (controller's name, action's name, action parameters) and generate url. Admittedly, this could have impact on application performance but gives you a very high level of maintainability.
September 11, 2017 11:49
Hi Scott, very happy to see you covering this, it's amazing!

By the way, like Valeriob mentioned, we're already fully compatible with Asp.Net Core 2.0. The project is referencing 1.1 for backwards compatibility, but it's also tested in production on Asp.Net Core 2.0 with .NET Standard 2.0!
September 11, 2017 12:56
when you are using Resharper seems quite useless. Resharper is able to analyze ASP.NET project and provide intellisense as well as static analysis for parameters which accept view's, controller's and actions's names.

Sure, but R4Mvc isn't only used for action names, it goes further by also hard-typing the parameters that are passed to them. Furthermore, it ensures the links you created will link to the correct area, which you sometimes have to be careful with asp.net.

On top of that, it also ensures that the pages will work at run-time as well. Resharper is good and all, but it'll only provide develop time hints, and you can ignore/forget them. You could rename your action, and forget to update the view, and you'll know about it only when a user visits the page. T4MVC and R4Mvc ensure that you'll catch this error during build time (assuming you're building views as part of your test/deploy process)

Regarding Link TagHelper - providing controller's name, action's name and action's parameters as a separated attributes is very inconvenient and hard to maintain. It should be used with some helper with accepts Expression<Action<T>> as main parameter


Actually… :)

&lt;a asp-action="Details" asp-controller="Dinners" asp-route-id="@Model.DinnerID" &gt;Dinner Details&lt;/a&gt;


This is the standard ASP.NET Core MVC Tag Helper. That's what we're trying to get away from. R4MVC allows you to change the above to:

&lt;a a mvc-action="MVC.Dinners.Details(Model.DinnerID)" &gt;Dinner Details&lt;/a&gt;


The call to the action is considerably more readable, is strongly typed, the parameters are properly handled and validated. All this for practically no overhead at runtime. And, like you said, "gives you a very high level of maintainability."
September 11, 2017 12:57
P.S. This comments area should handle "pre" tags better :)

Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.