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

ASP.NET Core 2 Identity/EF:如何获取用户类自定义属性并服务端缓存?

当然有可行的方案!你不用每次都写单独的查询方法,通过扩展ASP.NET Identity的机制,结合缓存,就能让await _userManager.GetUserAsync(User)返回包含所有自定义属性的用户对象。下面给你几个实用的实现思路:

方案1:给UserManager写扩展方法,加载关联数据+缓存

你可以封装一个扩展方法,在里面手动Include需要的导航属性,同时加入缓存逻辑,这样每次调用这个方法就能拿到完整且缓存的用户数据:

public static class UserManagerExtensions
{
    public static async Task<ApplicationUser> GetFullUserAsync(
        this UserManager<ApplicationUser> userManager, 
        ClaimsPrincipal user,
        IMemoryCache cache) // 注入缓存服务
    {
        var userId = userManager.GetUserId(user);
        var cacheKey = $"FullUser_{userId}";

        // 先尝试从缓存获取
        if (cache.TryGetValue(cacheKey, out ApplicationUser cachedUser))
        {
            return cachedUser;
        }

        // 缓存未命中,查询数据库并Include导航属性
        var fullUser = await userManager.Users
            .Include(u => u.UserImage)
            // 如果有其他自定义属性,继续链式Include
            .SingleOrDefaultAsync(u => u.Id == userId);

        if (fullUser != null)
        {
            // 将用户对象存入缓存,设置30分钟过期时间(可按需调整)
            cache.Set(cacheKey, fullUser, new MemoryCacheEntryOptions
            {
                AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30)
            });
        }

        return fullUser;
    }
}

使用的时候,只要注入IMemoryCache,然后调用:

var currentUser = await _userManager.GetFullUserAsync(User, _cache);

注意:当用户的UserImage或其他属性更新后,记得删除对应缓存键,避免返回旧数据。比如更新后执行_cache.Remove($"FullUser_{userId}")。

方案2:自定义UserStore,自动加载导航属性

UserManager的GetUserAsync最终会调用UserStore的FindByIdAsync方法,所以你可以自定义UserStore,重写这个方法让它自动Include需要的关联数据:

public class CustomUserStore : UserStore<ApplicationUser>
{
    private readonly ApplicationDbContext _dbContext;

    public CustomUserStore(ApplicationDbContext dbContext, IdentityErrorDescriber describer = null)
        : base(dbContext, describer)
    {
        _dbContext = dbContext;
    }

    public override async Task<ApplicationUser> FindByIdAsync(string userId, CancellationToken cancellationToken = default)
    {
        // 查询时自动Include UserImage
        return await _dbContext.ApplicationUsers
            .Include(u => u.UserImage)
            .SingleOrDefaultAsync(u => u.Id == userId, cancellationToken);
    }

    // 如果需要通过用户名查询也返回完整数据,可以重写FindByNameAsync
    public override async Task<ApplicationUser> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken = default)
    {
        return await _dbContext.ApplicationUsers
            .Include(u => u.UserImage)
            .SingleOrDefaultAsync(u => u.NormalizedUserName == normalizedUserName, cancellationToken);
    }
}

然后在Program.cs里替换默认的UserStore:

builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddUserStore<CustomUserStore>() // 注册自定义UserStore
    .AddEntityFrameworkStores<ApplicationDbContext>();

这样之后,你原来的await _userManager.GetUserAsync(User)就能直接拿到带UserImage的用户对象了。如果要加缓存,可以在这个自定义UserStore的方法里结合缓存逻辑,或者搭配方案1的缓存思路。

方案3:EF Core二级缓存(可选)

如果想让EF自动缓存查询结果,可以使用EF Core的二级缓存拦截器,这样多次查询同一个用户时,EF会直接从缓存返回,不用每次访问数据库。不过这个是全局的缓存机制,适合减少重复查询的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:51:46