ASP.NET Core 2.0如何基于用户扩展属性渲染动态路由链接?
解决ASP.NET Core 2.0中_Layout.cshtml动态设置asp-route-id为当前用户StoreId的问题
没问题,我来帮你搞定这个动态渲染链接的需求。根据你的场景,我们可以通过几种不同的方式实现,下面是最常用的几个方案:
方案一:直接在_Layout视图中异步获取用户信息
这种方式最直接,适合快速实现。你需要在布局视图中注入UserManager和你的数据库上下文,然后异步查询当前用户的UserDetail数据:
- 首先在_Layout.cshtml顶部注入所需服务:
@inject UserManager<ApplicationUser> UserManager @inject YourAppNamespace.YourDbContext _context @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
- 在需要生成链接的位置,添加以下代码:
@{ // 获取当前登录用户 var currentUser = await UserManager.GetUserAsync(User); // 默认使用硬编码的1,防止没有UserDetail的情况 int storeId = 1; if (currentUser != null) { // 根据用户ID关联查询UserDetail var userDetail = await _context.UserDetails.FirstOrDefaultAsync(ud => ud.OwnerID == currentUser.Id); if (userDetail != null) { storeId = userDetail.StoreId; } } } <!-- 动态生成的链接 --> <a asp-controller="YourTargetController" asp-action="YourTargetAction" asp-route-id="@storeId">你的链接文本</a>
注意:因为用到了异步方法await,ASP.NET Core 2.0布局页默认支持异步渲染,不需要额外修改视图声明。
方案二:使用ViewComponent(更优雅的解耦方式)
如果不想把数据查询逻辑写在视图里,推荐用ViewComponent来封装这个逻辑,让代码更清晰可维护:
- 创建一个
StoreLinkViewComponent类:
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Identity; using System.Threading.Tasks; using YourAppNamespace.Models; using Microsoft.EntityFrameworkCore; namespace YourAppNamespace.ViewComponents { public class StoreLinkViewComponent : ViewComponent { private readonly UserManager<ApplicationUser> _userManager; private readonly YourDbContext _context; public StoreLinkViewComponent(UserManager<ApplicationUser> userManager, YourDbContext context) { _userManager = userManager; _context = context; } public async Task<IViewComponentResult> InvokeAsync(string controller, string action, string linkText) { var user = await _userManager.GetUserAsync(HttpContext.User); int storeId = 1; if (user != null) { var userDetail = await _context.UserDetails.FirstOrDefaultAsync(ud => ud.OwnerID == user.Id); if (userDetail != null) { storeId = userDetail.StoreId; } } // 传递参数给视图 ViewData["Controller"] = controller; ViewData["Action"] = action; ViewData["LinkText"] = linkText; ViewData["StoreId"] = storeId; return View(); } } }
- 创建ViewComponent的视图文件:在
Views/Shared/Components/StoreLink/目录下新建Default.cshtml:
<a asp-controller="@ViewData["Controller"]" asp-action="@ViewData["Action"]" asp-route-id="@ViewData["StoreId"]"> @ViewData["LinkText"] </a>
- 在_Layout.cshtml中调用这个ViewComponent:
@await Component.InvokeAsync("StoreLink", new { controller = "YourTargetController", action = "YourTargetAction", linkText = "你的链接文本" })
方案三:通过BaseController将用户数据放入ViewBag(全局复用)
如果你的应用很多地方都需要用到用户的UserDetail数据,可以在基础控制器中统一获取,然后放到ViewBag里供所有视图使用:
- 创建一个
BaseController类,所有其他控制器继承它:
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Identity; using System.Threading.Tasks; using YourAppNamespace.Models; using Microsoft.EntityFrameworkCore; namespace YourAppNamespace.Controllers { public class BaseController : Controller { protected readonly UserManager<ApplicationUser> _userManager; protected readonly YourDbContext _context; public BaseController(UserManager<ApplicationUser> userManager, YourDbContext context) { _userManager = userManager; _context = context; } public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { var user = await _userManager.GetUserAsync(User); if (user != null) { var userDetail = await _context.UserDetails.FirstOrDefaultAsync(ud => ud.OwnerID == user.Id); ViewBag.CurrentUserDetail = userDetail; } await base.OnActionExecutionAsync(context, next); } } }
- 在_Layout.cshtml中使用ViewBag的数据:
@{ var userDetail = ViewBag.CurrentUserDetail as UserDetail; int storeId = userDetail?.StoreId ?? 1; } <a asp-controller="YourTargetController" asp-action="YourTargetAction" asp-route-id="@storeId">你的链接文本</a>
注意事项
- 确保
UserDetail模型与ApplicationUser的关联正确:OwnerID字段对应AspNetUsers表的Id列 - 处理用户未登录或者没有对应的
UserDetail记录的情况,设置默认值(比如原来的1)避免报错 - 如果你使用的是异步查询,不要用同步的
FirstOrDefault()方法,一定要用FirstOrDefaultAsync()防止线程阻塞
内容的提问来源于stack exchange,提问作者JuValencia
相关产品推荐
相关产品推荐

