The Issue
The example project from the Razor Pages with Entity Framework Core in ASP.NET Core - Tutorial includes the following code:
<a asp-page="./Index"
asp-route-sortOrder="@Model.CurrentSort"
asp-route-pageIndex="@(Model.Students.PageIndex + 1)"
asp-route-currentFilter="@Model.CurrentFilter"
class="btn btn-primary @nextDisabled">
Next
</a>
Link to those lines in the project.
The route parameter names:
asp-route-sortOrder="@Model.CurrentSort"
asp-route-pageIndex="@(Model.Students.PageIndex + 1)"
asp-route-currentFilter="@Model.CurrentFilter"
are not strongly-typed. I.e. there could be a typo in any of the names (sortOrder, pageIndex, currentFilter) and the project will compile and run however the program will not function as expected.
Workaround - use LinkGenerator.GetPathByAction
This stackoverflow post discusses one workaround for the issue. The example there has the following a tag-helper:
<a class="btn btn-block
@(category == ViewBag.SelectedCategory
? "btn-primary": "btn-outline-secondary")"
asp-action="Index" asp-controller="Home"
asp-route-category="@category"
asp-route-productPage="1">
@category
</a>
It is rewritten in a more strongly-typed manner using LinkGenerator.GetPathByAction as follows:
<a class="btn btn-block @(category == ViewBag.SelectedCategory ? "btn-primary" : "btn-outline-secondary")"
href="@(
_linkGenerator.GetPathByAction(
nameof(HomeController.Index),
Regex.Replace(nameof(HomeController), "Controller$", String.Empty),
new IndexParameters()
{
Category = category,
ProductPage = 1
}))">
@category
</a>
This is more of a demonstration of what is theoretically possible in the form of a quick solution; it's not ideal for end users.
Workaround - R4MVC
Another approach is to use R4MVC.
Here's a video demonstrating R4MVC.
Downsides to R4MVC:
- Still in pre-release
- Not built-in to ASP.NET Core
Workaround - object for parameters
If we use a class to represent the parameters to OnGetAsync:
public class OnGetAsyncParameters
{
public SortOrder? SortOrder { get; set; }
public string CurrentFilter { get; set; }
public string SearchString { get; set; }
public int? PageIndex { get; set; }
}
then instead of:
<a asp-page="./Index"
asp-route-sortOrder="@Model.CurrentSort"
asp-route-pageIndex="@(Model.Students.PageIndex + 1)"
asp-route-currentFilter="@Model.CurrentFilter"
class="btn btn-primary @nextDisabled">
Next
</a>
we can use asp-all-route-data and generate a dictionary from an instance of OnGetAsyncParameters:
<a asp-page="./Index"
asp-all-route-data="to_dict(new OnGetAsyncParameters()
{
SortOrder = Model.CurrentSort,
PageIndex = Model.Students.PageIndex + 1,
CurrentFilter = Model.CurrentFilter
})"
class="btn btn-primary @nextDisabled">
Next
</a>
Link
where to_dict is the following utility function:
Dictionary<string, string> to_dict(object obj)
{
return obj
.GetType()
.GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public)
.ToDictionary(
prop => prop.Name,
prop =>
{
var val = prop.GetValue(obj, null);
return val == null ? "" : val.ToString();
});
}
In this case, OnGetAsync is updated to accept OnGetAsyncParameters:
public async Task OnGetAsync(OnGetAsyncParameters onGetAsyncParameters)
Link
Request
The request is for ASP.NET Core to have route parameters be more strongly-typed in a tag-helpers.
I understand that the priority may be low. I'd just like to request that it at least be on the roadmap. :-)
The Issue
The example project from the Razor Pages with Entity Framework Core in ASP.NET Core - Tutorial includes the following code:
Link to those lines in the project.
The route parameter names:
are not strongly-typed. I.e. there could be a typo in any of the names (
sortOrder,pageIndex,currentFilter) and the project will compile and run however the program will not function as expected.Workaround - use
LinkGenerator.GetPathByActionThis stackoverflow post discusses one workaround for the issue. The example there has the following
atag-helper:It is rewritten in a more strongly-typed manner using
LinkGenerator.GetPathByActionas follows:This is more of a demonstration of what is theoretically possible in the form of a quick solution; it's not ideal for end users.
Workaround - R4MVC
Another approach is to use R4MVC.
Here's a video demonstrating R4MVC.
Downsides to R4MVC:
Workaround - object for parameters
If we use a class to represent the parameters to
OnGetAsync:then instead of:
we can use
asp-all-route-dataand generate a dictionary from an instance ofOnGetAsyncParameters:Link
where
to_dictis the following utility function:In this case,
OnGetAsyncis updated to acceptOnGetAsyncParameters:Link
Request
The request is for ASP.NET Core to have route parameters be more strongly-typed in
atag-helpers.I understand that the priority may be low. I'd just like to request that it at least be on the roadmap. :-)