调用AddToRolesAsync触发Invalid Operation:连接已关闭错误求助
解决AddToRolesAsync抛出"Invalid Operation the connection is closed"异常
问题根源
异步方法误用
async voidCreateParent方法定义为async static void,在Configure中直接调用时,ASP.NET Core不会等待该异步方法执行完成,导致数据库上下文等资源提前被释放,触发连接关闭异常。手动创建
DBContext实例
代码中多次通过new DBContext()创建上下文实例,而非依赖注入获取,导致多个独立的上下文同时工作,连接管理混乱,部分实例可能被提前销毁并关闭数据库连接。上下文实例不统一
创建角色、用户使用context实例,检查用户存在却用db实例,最后调用db.SaveChangesAsync()保存,操作分散在不同上下文,数据状态不一致,还可能引发连接冲突。未及时保存上下文变更
创建角色、用户后未立即调用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
相关产品推荐
相关产品推荐

