22 Mar 2021
Often you need to put links in your ASP.NET MVC Core Views that take users to other controllers in your web app – like navigating to a details page for a particular record in the table. Or when building a primary, secondary or tertiary navigation. Or logging users in or out. Heck, you need links everywhere!
A very obvious (but wrong!) way is to hardcode relative paths to your controller’s actions in the
View, like <a href="/product/details/1">View product details</a>
. It’s super easy, right? What can
possibly go wrong? Actually, a lot of things. Just the tip of the iceberg:
?id=1
to positional ids, like
/products/1
, you’ll need to update all your hardcoded URLs.As you can see, hardcoding is a big pain in the rear. But what can you do instead? Fear not, there’s a solution that addresses all the above problems and more!
Let’s look into automatic link generation, and how you can pimp it up to make it type-safe, ensuring compile-time checking, so no 404s ever happen when you refactor your code by renaming controllers or their methods.
There are at least three different ways to make links in ASP.NET MVC Core:
HtmlHelperLinkExtensions.ActionLink
AKA @Html.ActionLink
extension method<a asp-* ...>
Url.Action()
extension methodUnfortunately, as it’s often the case with Microsoft’s docs, it’s quite cryptic. Like how the hell are you supposed to know, based on the very scant documentation, which particular method you need to call?
ActionLink(IHtmlHelper, String, String)
ActionLink(IHtmlHelper, String, String, Object)
ActionLink(IHtmlHelper, String, String, String)
ActionLink(IHtmlHelper, String, String, Object, Object)
ActionLink(IHtmlHelper, String, String, String, Object)
ActionLink(IHtmlHelper, String, String, String, Object, Object)
Instead of trying to explain what all these parameters mean, let me just show you the most common use cases of this extension method.
@Html.ActionLink("Link to Index action", "Index")
@Html.ActionLink("Link to Index action of Home controller", "Index", "Home")
@Html.ActionLink("Link to Index action of Home controller with id=100500 and name='John Doe'",
"Index", "Home",
new { id = 100500, name = "John Doe" })
@Html.ActionLink("Link to Index action of Home controller with id=100500 and name='John Doe' and CSS class",
"Index", "Home",
new { id = 100500, name = "John Doe" },
new { @class="css-class"})
Now let’s look into the parameters:
IHtmlHelper
, as it’s a type parameterlinkText
specifies the text that goes in between <a></a>
tags.actionName
specifies the action of the controller.controllerName
specifies the name of the controller without the “Controller” suffix. So Home
instead of HomeController
routeValues
specifies parameters for your actions. You can use both object
as in case of new
{ name = "value" }
, or an instance of generic dictionary IDictionary<TKey, TValue>
htmlAttributes
an object that contains additional HTML attributes for the <a>
tag, such as CSS
class nameThis extension method is to be called from Views:
While @Html.ActionLink()
is a carry-over left in ASP.NET Core for migration from .NET, the
brand-spanking new way of generating links is the Anchor Tag Helper. Sporting much improved
readability, it lets you do this:
Check out the documentation for the full list of supported attributes, these being the most important ones:
asp-controller
– target controllerasp-action
– target actionasp-route-{value}
– specify parameters for the actionasp-fragment
– specify URL fragment to be added after #
This example shows how to generate a link with parameters:
Not all links need to be generated in Views, sometimes you need to build links in your Controllers
too. UrlHelperExtensions
class has Url.Action
method that does just that. The documentation
is similarly obscure, but now you know how to navigate it.
Some examples:
Url.Action("Index", "Home")
Url.Action("Details", "Home", new { name = "John Doe", id = 100500})
All the examples above suffer from a fundamental problem: if you rename a controller or action method, the links will break, but you’ll only going to find out about it when trying to use them. That’s clearly not good enough.
Let’s further improve the link generation by bringing in compile-time checking and retrieval of the
data that we need. The following code uses Url.Action
with a custom method GetControllerName
and
nameof
operator to get names of Controller and Action:
In the similar fashion, you can use that approach with both @Html.ActionLink
and <a asp-controller="..."></a>
:
And that’s a one-line implementation of GetControllerName
utility function. The only reason we
need it is to get rid of the Controller
suffix at the end of the string.
In this article, we looked at different ways of generating links in Views and Controllers in ASP.NET Core MVC. We also looked at how to make the link generation process resilient to changes in your application and avoid breaking the links.
Download fully tested and 100% working Visual Studio solution with the source code used in this article for FREE – just enter your name and email in the form below, and I’ll send you the download link right away.
You will also get access to all the source code for all existing and new articles on the site, and access to my mailing list, which receives handy timesaving tips on .NET Core programming.