There are two cases where parameter transformers can be used:
- To modify the route that the framework generates automatically from the location of a Razor Page
- To modify a parameter value in a route
Modifying Page Routes
By default, the route for a particular page is constructed from its file location and name. For example, a Razor page located at
/Pages/SalesReports/RevenueReport.cshtml will have a route template of
SalesReports/RevenueReport
generated for it. Let's say that you prefer to have the page reachable at
sales-reports/revenue-report
instead. You could apply an
override route, but if you have multiple pages to override in the same manner, this approach can be time-consuming and brittle. Instead, you can create a parameter transformer to manage the process for all pages in the application.
A parameter transformer is a class that implements IOutboundParameterTransformer
. This interface has one method,
TransformOutbound
which returns a string. The body of the method performs the transformation:
In this simple example, the regular expression identifies separate words in a Pascal case string. It looks for instances in the string - the part of the route's default template that relates to the file path of the page - where an upper case letter follows a lower case letter (i.e. where a new word starts) and then inserts a hyphen between them. The resulting string is then converted to lower case and returned, replacing the default template for the route.
To get this to work, the parameter transformer needs to be registered in
Startup
:
The asp-page
attribute on the anchor tag helper still takes the original file name and path:
<a asp-page="salesreports/revenuereport">Revenue Report</a>
This is converted to the correct route template at runtime:
<a href="/sales-reports/revenue-report">Revenue Report</a>
Modifying Parameter Values
An obvious application for this feature is modifying route parameter values obtained dynamically from a database or similar, so that the resulting URL is SEO-friendly. The parameter value can be anything - the title of a news story, a product name and so on. In this case, the parameter transformer is registered and used in the same way as a custom constraint.
The following illustration features an extension method, borrowed from the answer to a Stackoverflow question: How does Stack Overflow generate its SEO-friendly URLs?
This is a pretty robust way to convert characters in any string to their ASCII equivalents so that they are safe to use in a URL, and then insert hyphens between words. If you want to use the
ToSlug
method prior to ASP.NET Core 2.2, you can do so in an anchor tag helper:
<a asp-page="product" asp-route-name="@Model.ProductName.ToSlug()">@Model.ProductName</a>
Rather than remembering to use this method in all places throughout the application where it is needed, you can instead create a parameter transformer that uses it:
This is registered in the ConfigureServices
method:
It is added to the ConstraintMap
in the same way as a custom constraint. However, it is not a constraint. But you add it to the route template as part of the @page directive in the same way as a constraint:
@page "{name:slug}"
Now, there is no need to use the ToSlug
method on the value provided to the name route parameter value in anchor tags. The parameter transformer calls it instead:
<a asp-page="product" asp-route-name="@Model.ProductName">@Model.ProductName</a>Assuming that the the value represented by
Model.ProductName
is "Original Frankfurter grüne Soße", the generated output for the anchor tag helper is:
<a href="/product/original-frankfurter-grune-sosse">Original Frankfurter grüne Soße</a>
Summary
Parameter transformers implement IOutboundParameterTransformer
and can act on two parts of the route: those added as a
PageRouteTransformerConvention
act on the part of the route generated from the location of the page. Those added to the
ConstraintMap
act on specific route parameters. Both enable centralisation of logic designed to modify the values in the route.