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

向已存在角色添加用户时任务被取消的问题排查

问题排查:用户分配角色时出现任务取消错误

现有数据

角色表

Role IdNameNormalizedName
59f5238-818e-40f9-b95a-fc65db67f253ParentParent

用户表

IdFirst NameSurname
b3e9d5ec-1ddf-4e57-bf00-1afc2e7f0582ParentOne

错误信息

The Task is cancelled
at
Microsoft.AspNetCore.Identity.UserManager`1.d__116.MoveNext()
at Web.SampleData.d__2.MoveNext() in
SampleData.cs:line 118

相关代码

分配角色方法

public static async Task<IdentityResult> 
           AssignRoles(IServiceProvider services, 
           string email, string[] roles)
{
  IdentityResult result = new IdentityResult();
  UserManager<ApplicationUser> _userManager = 
    services.GetService<UserManager<ApplicationUser>>();
   ApplicationUser user = await 
         _userManager.FindByEmailAsync(email);
   result = await _userManager.AddToRolesAsync(user, roles);            
   return result;
}

完整种子数据初始化方法

public static void CreateParent(IServiceProvider 
                                serviceProvider)
{
    var context = new DBContext();// 
     serviceProvider.GetService<DBContext>();
      string[] roles = new string[] { "Parent" };
      foreach (string role in roles)
      {
        var roleStore = new RoleStore<IdentityRole>(context);
        if (!context.Roles.Any(r => r.Name == role))
           {
             roleStore.CreateAsync(new IdentityRole(role));
            }
        }
        
        var user = new ApplicationUser
        {
            FirstName = "Parent",
            LastName = "One",
            Email = "parentone@apps-Test.com",
            NormalizedEmail = "parentone@apps-Test.com",
            UserName = "parentone@apps-Test.com",
            NormalizedUserName = "parentone@apps-Test.com",
            PhoneNumber = "+111111111111",
            EmailConfirmed = true,
            PhoneNumberConfirmed = true,
            SecurityStamp = Guid.NewGuid().ToString("D")
        };

        var db = new DBContext();
        if (!db.Users.Any(u => u.UserName == user.UserName))
        {
            var password = new PasswordHasher<ApplicationUser>();
            var hashed = password.HashPassword(user, "Test12345!");
            user.PasswordHash = hashed;
            var userStore = new UserStore<ApplicationUser> 
            (context);
            var result = userStore.CreateAsync(user);

        }

        AssignRoles(serviceProvider, user.Email, roles);
        db.SaveChangesAsync();
    }

Startup.cs调用代码

public void Configure(IApplicationBuilder app, 
   IWebHostEnvironment env,IServiceProvider service)
{
        SampleData.CreateParent(service);

}

角色已成功创建,但将用户添加到角色时出现任务取消错误,用户未被添加到aspnetuseroles表,请求排查原因。


问题原因及解决方法

核心问题:异步方法未正确等待

所有调用的异步方法都未使用await关键字,导致任务在未完成时就被终止,触发任务取消:

  • roleStore.CreateAsync(new IdentityRole(role)):创建角色的异步操作未等待,可能角色还未写入数据库就执行后续步骤
  • userStore.CreateAsync(user):创建用户的异步操作未等待,用户可能未持久化就尝试分配角色
  • AssignRoles(serviceProvider, user.Email, roles):分配角色的异步方法被当作同步方法调用,未等待完成
  • db.SaveChangesAsync():保存更改的异步操作未等待,数据未持久化就结束流程

次要问题:DbContext实例混乱

代码中多次自行创建DBContext实例(new DBContext()),而非从依赖注入获取,导致上下文状态不一致:

  • 创建用户用的是新实例db,但写入用户用的是另一个实例context
  • 不同上下文实例的操作无法共享状态,可能导致查询不到刚创建的用户/角色

解决步骤

1. 将种子方法改为异步,并正确等待所有异步操作

public static async Task CreateParentAsync(IServiceProvider serviceProvider)
{
    // 从DI获取DbContext,不要自行new
    var context = serviceProvider.GetService<DBContext>();
    string[] roles = new string[] { "Parent" };
    
    foreach (string role in roles)
    {
        var roleStore = new RoleStore<IdentityRole>(context);
        if (!context.Roles.Any(r => r.Name == role))
        {
            // 等待角色创建完成
            await roleStore.CreateAsync(new IdentityRole(role));
        }
    }
    
    var user = new ApplicationUser
    {
        FirstName = "Parent",
        LastName = "One",
        Email = "parentone@apps-Test.com",
        NormalizedEmail = "PARENTONE@APPS-TEST.COM", // 符合Identity默认大写规范化逻辑
        UserName = "parentone@apps-Test.com",
        NormalizedUserName = "PARENTONE@APPS-TEST.COM",
        PhoneNumber = "+111111111111",
        EmailConfirmed = true,
        PhoneNumberConfirmed = true,
        SecurityStamp = Guid.NewGuid().ToString("D")
    };

    // 使用同一个context实例查询用户
    if (!context.Users.Any(u => u.UserName == user.UserName))
    {
        var password = new PasswordHasher<ApplicationUser>();
        var hashed = password.HashPassword(user, "Test12345!");
        user.PasswordHash = hashed;
        var userStore = new UserStore<ApplicationUser>(context);
        // 等待用户创建完成
        await userStore.CreateAsync(user);
    }

    // 等待角色分配完成
    await AssignRoles(serviceProvider, user.Email, roles);
    // 等待保存更改完成
    await context.SaveChangesAsync();
}

2. 修改Startup.cs中的调用方式

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider service)
{
    // 异步执行种子数据,避免异步上下文问题
    SampleData.CreateParentAsync(service).GetAwaiter().GetResult();
    
    // 其他中间件配置...
}

3. 修正规范化名称

Identity默认会将NormalizedEmail和NormalizedUserName转为大写,手动设置时保持大写,避免后续查询(比如FindByEmailAsync)因大小写不匹配找不到用户。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 19:24:26