'Link not rendering when using asp-page TagHelper
I have one page that does not render a link in HTML when using the asp-page TagHelper. I have seen this before, but it was due to a typo or the page not existing.
Of the two links in the _Layout below,
- Users renders as
http://localhost/ReportGroups/Admin/Users
- Roles renders as
http://localhost/ReportGroups
- Navigating to Roles manually results in a 404 error.
_Layout.cshtml
The link is part of an Admin menu. The commented out FontAwesome icons are part of my testing. /Admin/Users
works fine, but /Admin/RoleList
does not work. It was previously /Admin/Roles
but I built a new copy of the file up in parts to see if anything was throwing an error, or if it was a reserved word.
@if (User.Identity.IsAuthenticated)
{
if (User.IsInRole("Admin"))
{
<div id="nav-admin">
<ul>
<li><a asp-page="/Admin/Users"> Users</a></li>@*< i class="fas fa-user-secret" title="Users"></i>*@
<li><a asp-page="/Admin/RoleList"> Roles</a></li>
@*<i class="fas fa-id-card" title="Roles"></i>*@
</ul>
</div>
}
}
RoleList.cshtml
@page "{roleId}/{userId}"
@model RoleListModel
@{
ViewData["PageTitle"] = "Admin Tools - Roles";
ViewData["IconClass"] = "";
ViewData["IconTitle"] = "Roles";
}
<table>
<thead>
<tr>
<th>Role</th>
<th>User Name</th>
<th>First Name</th>
<th>Last Name</th>
<th> </th>
</tr>
</thead>
<tbody>
@foreach (ApplicationRole role in Model.AppRoles)
{
<tr>
<td colspan="4"><strong>@role.Name</strong></td>
<td>
<a asp-page="/App/RoleEdit" asp-route-roleId="@role.Id"><i class="fas fa-edit"></i></a>
</td>
</tr>
IList<ApplicationUser> usersOfRole = Model.AppRoleUsersDict[role];
foreach (ApplicationUser user in usersOfRole)
{
<tr>
<td>@role.Name</td>
<td>@user.UserName</td>
<td>@user.FirstName</td>
<td>@user.LastName</td>
<td>
<form method="post" asp-page-handler="delete">
<button type="submit" asp-page="/App/GroupEdit" asp-page-handler="delete" asp-route-roleId="@role.Id" asp-route-userId="@user.Id">
<i class="fas fa-trash-alt" style="color:red"></i>
</button>
</form>
</td>
</tr>
}
}
</tbody>
</table>
RoleList.cshtml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Ctrack.ReportGroups.Data;
using Ctrack.ReportGroups.Identity;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace Ctrack.ReportGroups.Pages
{
public class RoleListModel : PageModel
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly RoleManager<ApplicationRole> _roleManager;
private readonly ApplicationDbContext _db;
public RoleListModel(
ApplicationDbContext db,
UserManager<ApplicationUser> userManager,
RoleManager<ApplicationRole> roleManager)
{
_db = db;
_userManager = userManager;
_roleManager = roleManager;
}
public IList<ApplicationRole> AppRoles { get; set; }
public IDictionary<ApplicationRole, IList<ApplicationUser>> AppRoleUsersDict { get; set; }
/// <summary>
/// List all Roles, and the Users assigned to them. Exposes a form to delete the relationship for each user.
/// </summary>
/// <returns>Task>IActionResult></returns>
public async Task<IActionResult> OnGetAsync()
{
AppRoles = _roleManager.Roles.ToList();
AppRoleUsersDict = new Dictionary<ApplicationRole, IList<ApplicationUser>>();
foreach (ApplicationRole role in AppRoles)
{
IList<ApplicationUser> usersOfRole = await _userManager.GetUsersInRoleAsync(role.Name);
AppRoleUsersDict.Add(role, usersOfRole);
}
return Page();
}
/// <summary>
/// Removes a role from a User
/// </summary>
/// <param name="roleId"><see langword="string"/> containing RoleId</param>
/// <param name="userId"><see langword="string"/> containing UserId</param>
/// <returns>Task>IActionResult></returns>
public async Task<IActionResult> OnPostDeleteAsync(string roleId, string userId)
{
ApplicationUser user = await _userManager.FindByIdAsync(userId);
ApplicationRole role = await _roleManager.FindByIdAsync(roleId);
try
{
await _userManager.RemoveFromRoleAsync(user, role.Name);
TempData["Notification"] = $"Successfully removed Role {role.Name} from User {user.UserName}.";
}
catch (Exception ex)
{
TempData["ErrorMessage"] = $"Exception {ex.GetType()} encountered while removing Role {role.Name} from User {user.UserName}.";
}
return Page();
}
}
}
_ViewImports.cshtml
@using Microsoft.AspNetCore.Identity
@using CtrackReportGroupsRtca
@using Ctrack.ReportGroups.Data
@using Ctrack.ReportGroups.Identity
@using System.Security.Claims
@using Microsoft.AspNetCore.Html;
@namespace Ctrack.ReportGroups.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Solution 1:[1]
The reason that it does not work is that you have not defined the roleId and userId values. Change your link to be something like this:
<a asp-page="/Admin/RoleList" asp-route-roleId="YourRoleID" asp-route-userId="YourUserID"> Roles</a>
Solution 2:[2]
I'm using .NET Core 2.2, and had a similar problem. I fixed it by using
asp-page="/ThePage/Index"
instead of
asp-page="/ThePage"
This might be cloaking another root issue though.
3rd party edit
As John pointed out aspnetcore/issues/7656 contains
In asp.net core Razor Pages, the asp-page anchor tag helper does not create the 'href' if we don't include the ".../Index" for default (index) pages inside sub folders.
and
This is by design. The argument to asp-page is a page name not a URL Path.
Solution 3:[3]
In my case, I forgot to include the @page
directive at the top of my page:
@page
<h1>Hello, world!</h1>
Solution 4:[4]
Include this code in your current _ViewImports.cshtml, Solve for me!
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | pitaridis |
Solution 2 | surfmuggle |
Solution 3 | Josh Noe |
Solution 4 | this.hart |