You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core 2.0 MVC中如何扩展UserManager以在_LoginPartial获取Name

解决在_LoginPartial视图中显示ApplicationUser的Name字段问题

我来给你两种实用的方案,都能达到你要的效果,你可以根据自己的场景选择:

方案一:扩展UserManager类,添加GetName方法

这种方法和UserManager.GetUserName的使用方式完全一致,适合需要实时从数据库获取最新Name的场景(比如用户可能随时修改Name)。

步骤1:创建UserManager扩展类

在你的项目里新建一个静态类(比如UserManagerExtensions.cs),写入以下代码:

using Microsoft.AspNetCore.Identity;

public static class UserManagerExtensions
{
    // 同步版本
    public static string GetName(this UserManager<ApplicationUser> userManager, ApplicationUser user)
    {
        // 如果Name为空,回退到UserName,避免显示空白
        return user?.Name ?? userManager.GetUserName(user);
    }

    // 异步版本(更符合Identity的异步设计)
    public static async Task<string> GetNameAsync(this UserManager<ApplicationUser> userManager, ApplicationUser user)
    {
        if (user == null)
            return null;
        
        // 如果你担心用户对象是缓存的,也可以先从数据库重新获取
        // var freshUser = await userManager.FindByIdAsync(user.Id);
        // return freshUser?.Name ?? await userManager.GetUserNameAsync(user);
        
        return user.Name ?? await userManager.GetUserNameAsync(user);
    }
}

步骤2:在_LoginPartial视图中使用

首先在视图顶部注入UserManager和SignInManager,然后获取当前用户并调用扩展方法:

@inject UserManager<ApplicationUser> UserManager
@inject SignInManager<ApplicationUser> SignInManager

@if (SignInManager.IsSignedIn(User))
{
    var currentUser = await UserManager.GetUserAsync(User);
    var displayName = await UserManager.GetNameAsync(currentUser);
    
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="" asp-controller="Manage" asp-action="Index" title="Manage">Hello @displayName!</a>
    </li>
    <li class="nav-item">
        <form class="form-inline" asp-area="" asp-controller="Account" asp-action="Logout">
            <button type="submit" class="nav-link btn btn-link text-dark">Logout</button>
        </form>
    </li>
}
else
{
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="" asp-controller="Account" asp-action="Login">Login</a>
    </li>
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="" asp-controller="Account" asp-action="Register">Register</a>
    </li>
}

方案二:通过ClaimsPrincipal扩展直接获取Name(性能更优)

这种方法把Name存入用户的Claim中,不需要每次查询数据库,适合Name不经常修改的场景,使用起来更简洁。

步骤1:自定义ClaimsPrincipal工厂

新建一个类CustomUserClaimsPrincipalFactory.cs,用来把Name添加到用户的Claim集合里:

using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using System.Security.Claims;
using System.Threading.Tasks;

public class CustomUserClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser>
{
    public CustomUserClaimsPrincipalFactory(UserManager<ApplicationUser> userManager, IOptions<IdentityOptions> optionsAccessor) 
        : base(userManager, optionsAccessor)
    {
    }

    protected override async Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user)
    {
        var identity = await base.GenerateClaimsAsync(user);
        // 如果Name不为空,就添加到Claim里
        if (!string.IsNullOrEmpty(user.Name))
        {
            identity.AddClaim(new Claim(ClaimTypes.GivenName, user.Name));
        }
        return identity;
    }
}

步骤2:在Startup.cs中注册自定义工厂

找到ConfigureServices方法,添加以下注册代码:

services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, CustomUserClaimsPrincipalFactory>();

步骤3:创建ClaimsPrincipal扩展方法

新建静态类ClaimsPrincipalExtensions.cs:

using System.Security.Claims;

public static class ClaimsPrincipalExtensions
{
    public static string GetName(this ClaimsPrincipal principal)
    {
        // 先找我们添加的GivenName Claim,找不到就回退到默认的Name(也就是UserName)
        var nameClaim = principal.FindFirst(ClaimTypes.GivenName) ?? principal.FindFirst(ClaimTypes.Name);
        return nameClaim?.Value ?? string.Empty;
    }
}

步骤4:在视图中直接使用

现在视图里不需要注入UserManager了,直接调用扩展方法即可:

@inject SignInManager<ApplicationUser> SignInManager

@if (SignInManager.IsSignedIn(User))
{
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="" asp-controller="Manage" asp-action="Index" title="Manage">Hello @User.GetName()!</a>
    </li>
    // ... 其他登出代码
}
else
{
    // ... 登录注册代码
}

两种方案对比

  • 方案一:实时获取数据库中的Name,适合Name经常变动的场景,但每次都要查询数据库(可以通过缓存优化)。
  • 方案二:从Cookie中的Claim读取,性能更好,但Name修改后需要用户重新登录才能更新显示。

内容的提问来源于stack exchange,提问作者user6383418

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 06:43:02