Anchor Tag Helper in ASP.NET Core

By Peter Kellner and Scott Addie

The Anchor Tag Helper enhances the standard HTML anchor (<a ... ></a>) tag by adding new attributes. By convention, the attribute names are prefixed with asp-. The rendered anchor element's href attribute value is determined by the values of the asp- attributes.

For an overview of Tag Helpers, see Tag Helpers in ASP.NET Core.

View or download sample code (how to download)

SpeakerController is used in samples throughout this document:

using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;

public class SpeakerController : Controller
{
    private List<Speaker> Speakers =
        new List<Speaker>
        {
            new Speaker {SpeakerId = 10},
            new Speaker {SpeakerId = 11},
            new Speaker {SpeakerId = 12}
        };

    [Route("Speaker/{id:int}")]
    public IActionResult Detail(int id) =>
        View(Speakers.FirstOrDefault(a => a.SpeakerId == id));

    [Route("/Speaker/Evaluations", 
           Name = "speakerevals")]
    public IActionResult Evaluations() => View();

    [Route("/Speaker/EvaluationsCurrent",
           Name = "speakerevalscurrent")]
    public IActionResult Evaluations(
        int speakerId,
        bool currentYear) => View();

    public IActionResult Index() => View(Speakers);
}

public class Speaker
{
    public int SpeakerId { get; set; }
}

An inventory of the asp- attributes follows.

asp-controller

The asp-controller attribute assigns the controller used for generating the URL. The following markup lists all speakers:

<a asp-controller="Speaker"
   asp-action="Index">All Speakers</a>

The generated HTML:

<a href="/Speaker">All Speakers</a>

If the asp-controller attribute is specified and asp-action isn't, the default asp-action value is the controller action associated with the currently executing view. If asp-action is omitted from the preceding markup, and the Anchor Tag Helper is used in HomeController's Index view (/Home), the generated HTML is:

<a href="/Home">All Speakers</a>

asp-action

The asp-action attribute value represents the controller action name included in the generated href attribute. The following markup sets the generated href attribute value to the speaker evaluations page:

<a asp-controller="Speaker"
   asp-action="Evaluations">Speaker Evaluations</a>

The generated HTML:

<a href="/Speaker/Evaluations">Speaker Evaluations</a>

If no asp-controller attribute is specified, the default controller calling the view executing the current view is used.

If the asp-action attribute value is Index, then no action is appended to the URL, leading to the invocation of the default Index action. The action specified (or defaulted), must exist in the controller referenced in asp-controller.

asp-route-{value}

The asp-route-{value} attribute enables a wildcard route prefix. Any value occupying the {value} placeholder is interpreted as a potential route parameter. If a default route isn't found, this route prefix is appended to the generated href attribute as a request parameter and value. Otherwise, it's substituted in the route template.

Consider the following controller action:

public IActionResult AnchorTagHelper(int id)
{
    var speaker = new Speaker
    {
        SpeakerId = id
    };

    return View(speaker);
}

With a default route template defined in Startup.Configure:

app.UseMvc(routes =>
{
    // need route and attribute on controller: [Area("Blogs")]
    routes.MapRoute(name: "areaRoute",
                    template: "{area:exists}/{controller=Home}/{action=Index}");

    // default route for non-areas
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
});

The MVC view uses the model, provided by the action, as follows:

@model Speaker
<!DOCTYPE html>
<html>
<body>
    <a asp-controller="Speaker"
       asp-action="Detail" 
       asp-route-id="@Model.SpeakerId">SpeakerId: @Model.SpeakerId</a>
</body>
</html>

The default route's {id?} placeholder was matched. The generated HTML:

<a href="/Speaker/Detail/12">SpeakerId: 12</a>

Assume the route prefix isn't part of the matching routing template, as with the following MVC view:

@model Speaker
<!DOCTYPE html>
<html>
<body>
    <a asp-controller="Speaker" 
       asp-action="Detail" 
       asp-route-speakerid="@Model.SpeakerId">SpeakerId: @Model.SpeakerId</a>
<body>
</html>

The following HTML is generated because speakerid wasn't found in the matching route:

<a href="/Speaker/Detail?speakerid=12">SpeakerId: 12</a>

If either asp-controller or asp-action aren't specified, then the same default processing is followed as is in the asp-route attribute.

asp-route

The asp-route attribute is used for creating a URL linking directly to a named route. Using routing attributes, a route can be named as shown in the SpeakerController and used in its Evaluations action:

[Route("/Speaker/Evaluations", 
       Name = "speakerevals")]
public IActionResult Evaluations() => View();

In the following markup, the asp-route attribute references the named route:

<a asp-route="speakerevals">Speaker Evaluations</a>

The Anchor Tag Helper generates a route directly to that controller action using the URL /Speaker/Evaluations. The generated HTML:

<a href="/Speaker/Evaluations">Speaker Evaluations</a>

If asp-controller or asp-action is specified in addition to asp-route, the route generated may not be what you expect. To avoid a route conflict, asp-route shouldn't be used with the asp-controller and asp-action attributes.

asp-all-route-data

The asp-all-route-data attribute supports the creation of a dictionary of key-value pairs. The key is the parameter name, and the value is the parameter value.

In the following example, a dictionary is initialized and passed to a Razor view. Alternatively, the data could be passed in with your model.

@{
var parms = new Dictionary<string, string>
            {
                { "speakerId", "11" },
                { "currentYear", "true" }
            };
}

<a asp-route="speakerevalscurrent"
   asp-all-route-data="parms">Speaker Evaluations</a>

The preceding code generates the following HTML:

<a href="/Speaker/EvaluationsCurrent?speakerId=11&currentYear=true">Speaker Evaluations</a>

The asp-all-route-data dictionary is flattened to produce a querystring meeting the requirements of the overloaded Evaluations action:

[Route("/Speaker/EvaluationsCurrent",
       Name = "speakerevalscurrent")]
public IActionResult Evaluations(
    int speakerId,
    bool currentYear) => View();

If any keys in the dictionary match route parameters, those values are substituted in the route as appropriate. The other non-matching values are generated as request parameters.

asp-fragment

The asp-fragment attribute defines a URL fragment to append to the URL. The Anchor Tag Helper adds the hash character (#). Consider the following markup:

<a asp-controller="Speaker"
   asp-action="Evaluations"
   asp-fragment="SpeakerEvaluations">Speaker Evaluations</a>

The generated HTML:

<a href="/Speaker/Evaluations#SpeakerEvaluations">Speaker Evaluations</a>

Hash tags are useful when building client-side apps. They can be used for easy marking and searching in JavaScript, for example.

asp-area

The asp-area attribute sets the area name used to set the appropriate route. The following example depicts how the area attribute causes a remapping of routes. Setting asp-area to "Blogs" prefixes the directory Areas/Blogs to the routes of the associated controllers and views for this anchor tag.

  • {Project name}
    • wwwroot
    • Areas
      • Blogs
        • Controllers
          • HomeController.cs
        • Views
          • Home
            • AboutBlog.cshtml
            • Index.cshtml
          • _ViewStart.cshtml
    • Controllers

Given the preceding directory hierarchy, the markup to reference the AboutBlog.cshtml file is:

<a asp-area="Blogs"
   asp-controller="Home"
   asp-action="AboutBlog">About Blog</a>

The generated HTML:

<a href="/Blogs/Home/AboutBlog">About Blog</a>

Tip

For areas to work in an MVC app, the route template must include a reference to the area, if it exists. That template is represented by the second parameter of the routes.MapRoute method call in Startup.Configure:

app.UseMvc(routes =>
{
    // need route and attribute on controller: [Area("Blogs")]
    routes.MapRoute(name: "areaRoute",
                    template: "{area:exists}/{controller=Home}/{action=Index}");

    // default route for non-areas
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
});

asp-protocol

The asp-protocol attribute is for specifying a protocol (such as https) in your URL. For example:

<a asp-protocol="https"
   asp-controller="Home"
   asp-action="About">About</a>

The generated HTML:

<a href="https://localhost/Home/About">About</a>

The host name in the example is localhost, but the Anchor Tag Helper uses the website's public domain when generating the URL.

asp-host

The asp-host attribute is for specifying a host name in your URL. For example:

<a asp-protocol="https"
   asp-host="microsoft.com"
   asp-controller="Home"
   asp-action="About">About</a>

The generated HTML:

<a href="https://microsoft.com/Home/About">About</a>

asp-page

The asp-page attribute is used with Razor Pages. Use it to set an anchor tag's href attribute value to a specific page. Prefixing the page name with a forward slash ("/") creates the URL.

The following sample points to the attendee Razor Page:

<a asp-page="/Attendee">All Attendees</a>

The generated HTML:

<a href="/Attendee">All Attendees</a>

The asp-page attribute is mutually exclusive with the asp-route, asp-controller, and asp-action attributes. However, asp-page can be used with asp-route-{value} to control routing, as the following markup demonstrates:

<a asp-page="/Attendee"
   asp-route-attendeeid="10">View Attendee</a>

The generated HTML:

<a href="/Attendee?attendeeid=10">View Attendee</a>

asp-page-handler

The asp-page-handler attribute is used with Razor Pages. It's intended for linking to specific page handlers.

Consider the following page handler:

public void OnGetProfile(int attendeeId)
{
    ViewData["AttendeeId"] = attendeeId;

    // code omitted for brevity
}

The page model's associated markup links to the OnGetProfile page handler. Note that the On<Verb> prefix of the page handler method name is omitted in the asp-page-handler attribute value. If this were an asynchronous method, the Async suffix would be omitted too.

<a asp-page="/Attendee"
   asp-page-handler="Profile"
   asp-route-attendeeid="12">Attendee Profile</a>

The generated HTML:

<a href="/Attendee?attendeeid=12&handler=Profile">Attendee Profile</a>

Additional resources