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

重写返回Task的方法添加async时出现StackOverflow异常

解决ASP.NET Identity 2.2.1中重写FindByIdAsync导致的StackOverflow异常

你遇到的栈溢出问题根源很明确:无限递归调用。

为什么会出现递归?

默认的UserManager.GetRolesAsync()方法内部逻辑会先调用FindByIdAsync()来确认用户的有效性——而你重写的FindByIdAsync()又调用了this.GetRolesAsync(),这就形成了一个死循环:
MyUserManager.FindByIdAsync() → base.FindByIdAsync() → this.GetRolesAsync() → 内部触发FindByIdAsync() → 回到你的重写方法,反复调用直到栈被撑爆。

解决方案:绕过UserManager的GetRolesAsync,直接查询角色数据

要避免递归,我们需要跳过UserManager封装的GetRolesAsync(),直接从底层数据存储(比如EF的DbContext)查询用户的角色信息。

方法1:直接通过DbContext查询(推荐)

如果你的项目使用Entity Framework作为存储,直接注入DbContext并查询用户角色关联表:

public class MyUserManager : UserManager<MyUser>, IMyUserManager
{
    private readonly ApplicationDbContext _dbContext;

    // 构造函数注入DbContext和其他必要依赖
    public MyUserManager(IUserStore<MyUser> userStore, ApplicationDbContext dbContext, 
        IPasswordHasher<MyUser> passwordHasher, /* 其他需要的服务 */)
        : base(userStore)
    {
        _dbContext = dbContext;
        PasswordHasher = passwordHasher;
        // 其他初始化配置...
    }

    public override async Task<MyUser> FindByIdAsync(string userId)
    {
        var user = await base.FindByIdAsync(userId);
        if (user == null)
        {
            return null;
        }

        // 直接从数据库查询用户的角色名称,跳过UserManager的GetRolesAsync
        user.RoleNames = await _dbContext.UserRoles
            .Where(ur => ur.UserId == userId)
            .Join(_dbContext.Roles, 
                  ur => ur.RoleId, 
                  r => r.Id, 
                  (ur, r) => r.Name)
            .ToListAsync();

        return user;
    }
}

方法2:通过RoleStore查询

如果你更倾向于使用Identity的Store接口而非直接操作DbContext,可以注入IRoleStore来查询角色:

public class MyUserManager : UserManager<MyUser>, IMyUserManager
{
    private readonly IRoleStore<IdentityRole, string> _roleStore;
    private readonly IUserRoleStore<MyUser, string> _userRoleStore;

    public MyUserManager(IUserStore<MyUser> userStore, IRoleStore<IdentityRole, string> roleStore,
        /* 其他依赖 */)
        : base(userStore)
    {
        _roleStore = roleStore;
        _userRoleStore = userStore as IUserRoleStore<MyUser, string>;
        // 初始化配置...
    }

    public override async Task<MyUser> FindByIdAsync(string userId)
    {
        var user = await base.FindByIdAsync(userId);
        if (user == null)
        {
            return null;
        }

        // 获取用户关联的角色ID集合
        var roleIds = await _userRoleStore.GetRolesAsync(user);
        // 批量查询角色实体并提取名称
        var roles = new List<IdentityRole>();
        foreach (var roleId in roleIds)
        {
            var role = await _roleStore.FindByIdAsync(roleId);
            if (role != null)
            {
                roles.Add(role);
            }
        }
        user.RoleNames = roles.Select(r => r.Name).ToList();

        return user;
    }
}

注意事项

  • 确保DI容器正确注入所有需要的依赖(DbContext、各种Store等),避免出现注入错误。
  • 如果你使用的是自定义的IdentityRole或IdentityUserRole,需要调整代码中的泛型类型和查询逻辑,匹配你的实体定义。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:25:57