T4MVC and R4MVC - Roslyn code generators for ASP.NET Core tag helpers
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."
I'll run "Generate-R4MVC" in the Package Manager Console.
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.
When returning a view, rather than return View("About") I can do return View(Views.About):
The R4MVC project also has Tag Helpers so their mvc-action attribute gives you strong typing like this:
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.
About Newsletter
I wanted to say that it already supports aspnetcore 2.0 !
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).
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.
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.
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!
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… :)
<a asp-action="Details" asp-controller="Dinners" asp-route-id="@Model.DinnerID" >Dinner Details</a>
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:
<a a mvc-action="MVC.Dinners.Details(Model.DinnerID)" >Dinner Details</a>
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."
Comments are closed.
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.