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

调用AddToRolesAsync触发Invalid Operation:连接已关闭错误求助

解决AddToRolesAsync抛出"Invalid Operation the connection is closed"异常

问题根源

  1. 异步方法误用async void
    CreateParent方法定义为async static void,在Configure中直接调用时,ASP.NET Core不会等待该异步方法执行完成,导致数据库上下文等资源提前被释放,触发连接关闭异常。

  2. 手动创建DBContext实例
    代码中多次通过new DBContext()创建上下文实例,而非依赖注入获取,导致多个独立的上下文同时工作,连接管理混乱,部分实例可能被提前销毁并关闭数据库连接。

  3. 上下文实例不统一
    创建角色、用户使用context实例,检查用户存在却用db实例,最后调用db.SaveChangesAsync()保存,操作分散在不同上下文,数据状态不一致,还可能引发连接冲突。

  4. 未及时保存上下文变更
    创建角色、用户后未立即调用SaveChangesAsync(),数据未持久化,UserManager操作时可能无法找到对应数据,或上下文连接已被关闭。


修复后的代码

1. 修正CreateParent方法

public async static Task CreateParent(IServiceProvider serviceProvider)
{
    // 从依赖注入获取统一的DBContext实例
    using 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));
            // 创建角色后立即保存变更
            await context.SaveChangesAsync();
        }
    }
        
    var user = new ApplicationUser
    {
        FirstName = "Parent",
        LastName = "Two",
        Email = "parenttwo@apps-mobileapp.com",
        NormalizedEmail = "PARENTTWO@APPS-MOBILEAPP.COM",
        UserName = "parenttwo@apps-MOBILEAPP.com",
        NormalizedUserName = "PARENTTWO@APPS-MOBILEAPP.COM",
        PhoneNumber = "+111111111111",
        EmailConfirmed = true,
        PhoneNumberConfirmed = true,
        SecurityStamp = Guid.NewGuid().ToString("D")
    };

    // 使用同一个上下文检查用户是否存在
    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);
        var result = await userStore.CreateAsync(user);
        // 创建用户后立即保存变更
        await context.SaveChangesAsync();
    }

    await AssignRoles(serviceProvider, user, user.Email, roles);
}

2. 优化AssignRoles方法

public static async Task<IdentityResult> AssignRoles(IServiceProvider services, ApplicationUser user, string email, string[] roles)
{
    // 使用GetRequiredService确保获取到UserManager实例
    var userManager = services.GetRequiredService<UserManager<ApplicationUser>>();            
    return await userManager.AddToRolesAsync(user, roles);
 }

3. 修正Startup中调用逻辑

Configure方法不能标记为async,需通过IHostApplicationLifetime的事件执行异步初始化:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider)
{
    // 应用启动完成后执行异步初始化逻辑
    var appLifetime = serviceProvider.GetRequiredService<IHostApplicationLifetime>();
    appLifetime.ApplicationStarted.Register(async () =>
    {
        await SampleData.CreateParent(serviceProvider);
    });

    // 其他中间件配置代码...
}

核心修复要点

  • 将async static void改为async static Task,确保异步操作能被正确等待。
  • 统一通过依赖注入获取DBContext,禁止手动实例化,让框架管理上下文生命周期。
  • 每次创建角色、用户后立即调用SaveChangesAsync(),保证数据持久化。
  • 使用IHostApplicationLifetime.ApplicationStarted事件执行异步初始化,避免阻塞应用启动且确保操作完成。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 21:15:37