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

ASP.Net Core中控制器动作查询ApplicationUser的最优方式探讨

优化ASP.NET Core中获取自定义ApplicationUser字段的方案

你的当前做法可行但并非最优,频繁在每个控制器动作中查询数据库会增加数据库负载,尤其是高并发场景下。下面给出几种更合理的优化方案,按需选择:

方案1:将自定义字段存入Claims(推荐用于不常变更的字段)

把用户的自定义字段直接添加到登录时生成的Claims中,后续请求可直接从User.Claims读取,无需查询数据库。

实现步骤:

在登录逻辑中,找到用户后将自定义字段加入ClaimsIdentity:

var user = await _userManager.FindByEmailAsync(model.Email);
if (user != null && await _userManager.CheckPasswordAsync(user, model.Password))
{
    var claims = new List<Claim>
    {
        new Claim(ClaimTypes.NameIdentifier, user.Id),
        // 添加自定义字段到Claims
        new Claim("UserNickname", user.Nickname),
        new Claim("IsPremium", user.IsPremium.ToString())
    };

    var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
    await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity));
    
    return RedirectToAction("Index", "Home");
}

后续在控制器中直接读取:

var nickname = User.FindFirstValue("UserNickname");
var isPremium = bool.Parse(User.FindFirstValue("IsPremium"));

优点:完全避免数据库查询,性能最优;缺点:字段更新后需用户重新登录才会同步Claims中的数据,适合不频繁变更的字段。

方案2:缓存用户信息(适合字段经常变更的场景)

使用内存缓存或分布式缓存(如Redis)存储用户信息,减少重复查询数据库的次数。

实现步骤:

  1. 注册缓存服务(ASP.NET Core默认已注入IMemoryCache,分布式缓存需额外配置)
  2. 封装一个获取缓存用户的服务:
public class CurrentUserService
{
    private readonly IMemoryCache _cache;
    private readonly UserManager<ApplicationUser> _userManager;
    private const string CacheKeyPrefix = "AppUser_";

    public CurrentUserService(IMemoryCache cache, UserManager<ApplicationUser> userManager)
    {
        _cache = cache;
        _userManager = userManager;
    }

    public async Task<ApplicationUser> GetUserAsync(ClaimsPrincipal user)
    {
        var userId = user.FindFirstValue(ClaimTypes.NameIdentifier);
        if (string.IsNullOrEmpty(userId)) return null;

        return await _cache.GetOrCreateAsync($"{CacheKeyPrefix}{userId}", async entry =>
        {
            // 设置缓存过期时间,按需调整
            entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(15);
            return await _userManager.FindByIdAsync(userId);
        });
    }
}
  1. 在控制器中注入并使用:
private readonly CurrentUserService _currentUserService;

public HomeController(CurrentUserService currentUserService)
{
    _currentUserService = currentUserService;
}

public async Task<IActionResult> Index()
{
    var user = await _currentUserService.GetUserAsync(User);
    // 使用user的自定义字段
    return View();
}

优点:大幅减少数据库查询,字段变更后会在缓存过期后自动同步;缺点:占用缓存资源,分布式部署需使用Redis等分布式缓存保证一致性。

方案3:用ActionFilter统一获取用户信息(减少重复代码)

如果多个控制器都需要获取用户信息,可编写ActionFilter在请求进入Action前统一查询(可结合缓存),将用户信息存入HttpContext.Items,避免每个Action重复写查询代码。

实现示例:

public class CurrentUserFilter : IAsyncActionFilter
{
    private readonly CurrentUserService _userService;

    public CurrentUserFilter(CurrentUserService userService)
    {
        _userService = userService;
    }

    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        var user = await _userService.GetUserAsync(context.HttpContext.User);
        if (user != null)
        {
            context.HttpContext.Items["CurrentUser"] = user;
        }
        await next();
    }
}

注册Filter:

builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add<CurrentUserFilter>();
});

控制器中读取:

var user = HttpContext.Items["CurrentUser"] as ApplicationUser;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 14:32:11