ASP.NET Core 2.2 Parameter Transformers for clean URL generation and slugs in Razor Pages or MVC
I noticed that last week .NET Core 2.2 Preview 3 was released:
You can download and get started with .NET Core 2.2, on Windows, macOS, and Linux:
- .NET Core 2.2 Preview 3 SDK (includes the runtime)
- .NET Core 2.2 Preview 3 Runtime
Docker images are available at microsoft/dotnet for .NET Core and ASP.NET Core.
.NET Core 2.2 Preview 3 can be used with Visual Studio 15.9 Preview 3 (or later), Visual Studio for Mac and Visual Studio Code.
The feature I am most stoked about in ASP.NET 2.2 is a subtle one but I remember implementing it manually many times over the last 10 years. I'm happy to see it nicely integrated into ASP.NET Core's MVC and Razor Pages patterns.
ASP.NET Core 2.2 introduces the concept of Parameter Transformers to routing. Remember there isn't a directly relationship between what's in the URL/Address bar and what's on disk. The routing subsystem handles URLs coming in from the client and routes them to Controllers, but it also generates URLs (strings) when given an Controller and Action.
So if I'm using Razor Pages and I have a file Pages/FancyPants.cshtml I can get to it by default at /FancyPants. I can also "ask" for the URL when I'm creating anchors/links in my Razor Page:
<a class="nav-link text-dark" asp-area="" asp-page="/fancypants">Fancy Pants</a>
Here I'm asking for the page. That asp-page attribute points to a logical page, not a physical file.
We can make an IOutboundParameterTransformer that changes URLs to a format (for example) like a WordPress standard slug in the two-words format.
public class SlugifyParameterTransformer : IOutboundParameterTransformer { public string TransformOutbound(object value) { if (value == null) { return null; } // Slugify value return Regex.Replace(value.ToString(), "([a-z])([A-Z])", "$1-$2").ToLower(); } }
Then you let the ASP.NET Pipeline know about this transformer, either in Razor Pages...
services.AddMvc() .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) .AddRazorPagesOptions(options => { options.Conventions.Add( new PageRouteTransformerConvention( new SlugifyParameterTransformer())); });
or in ASP.NET MVC:
services.AddMvc(options => { options.Conventions.Add(new RouteTokenTransformerConvention( new SlugifyParameterTransformer())); });
Now when I run my application, I get my routing both coming in (from the client web browser) and going out (generated via Razor pages. Here I'm hovering over the "Fancy Pants" link at the top of the page. Notice that it's generated /fancy-pants as the URL.
So that same code from above that generates anchor tags <a href= gives me the expected new style of URL, and I only need to change it in one location.
There is also a new service called LinkGenerator that's a singleton you can call outside the context of an HTTP call (without an HttpContext) in order to generate a URL string.
return _linkGenerator.GetPathByAction( httpContext, controller: "Home", action: "Index", values: new { id=42 });
This can be useful if you are generating URLs outside of Razor or in some Middleware. There's a lot more little subtle improvements in ASP.NET Core 2.2, but this was the one that I will find the most useful in the near term.
Sponsor: Check out the latest JetBrains Rider with built-in spell checking, enhanced debugger, Docker support, full C# 7.3 support, publishing to IIS and more advanced Unity support.
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
In Scott's example only "fancy-pants" will return the HTML content. "FancyPants" will 404.
The link generator could be a (small) step into that direction. :)
// Ryan
Comments are closed.