.NET Core 2.0中AspNetUsers表事务不生效问题求助
解决ASP.NET Core Identity事务不一致问题
你遇到的核心问题是_userManager.CreateAsync方法内部会自动调用SaveChanges()提交AspNetUser表的修改,导致这部分操作脱离了你手动创建的事务控制,出现了部分表数据提前保存的情况。下面给你两种可行的解决方案,以及问题根源的详细解释:
解决方案一:使用TransactionScope统一管理事务
这种方式可以让所有操作(包括Identity的用户创建)都处于同一个事务上下文,只要不调用Complete(),所有变更都会在异常时自动回滚。
第一步:配置DbContext支持事务
在Startup.cs的ConfigureServices中,修改DbContext的注册代码,开启事务支持:
public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddDbContext<ApplicationDbContext>(options => { IConfigurationRoot configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json") .Build(); // 配置SQL Server并启用事务支持 options.UseSqlServer(configuration["ConnectionStrings:IdentityConnection"], o => o.EnableRetryOnFailure().EnlistTransaction(Transaction.Current)); },ServiceLifetime.Scoped); // 其他Identity相关注册代码... }
第二步:修改Register方法使用TransactionScope
public async Task<IActionResult> Register([FromBody]AccountBindingViewModel model) { // 启用异步事务流支持 using (var transactionScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)) { try { // 保存自定义Users表数据 applicationDbContext.Add(new Users() { Name = "Rishi" }); await applicationDbContext.SaveChangesAsync(); // 创建Identity用户 var user = new ApplicationUser { UserName = model.Email, Email = model.Email, PhoneNumber = model.PhoneNumber }; var result = await _userManager.CreateAsync(user, model.Password); if (result.Succeeded) { var savedUser = await _userManager.FindByEmailAsync(model.Email); if (savedUser != null) { SaveEntity(savedUser, model); // 保存其他表数据 // throw new Exception(); // 测试回滚时可以取消注释 transactionScope.Complete(); // 确认提交所有事务 } } return Ok(); } catch (Exception ex) { // 异常时事务自动回滚 return BadRequest(new { Message = "注册失败:" + ex.Message }); } } }
解决方案二:手动控制Identity用户的保存流程
绕过UserManager.CreateAsync的自动保存逻辑,手动处理用户密码哈希并将用户添加到DbContext,让所有变更都由你手动控制提交。
public async Task<IActionResult> Register([FromBody]AccountBindingViewModel model) { using (var dbTransaction = await applicationDbContext.Database.BeginTransactionAsync()) { try { // 保存自定义Users表数据 applicationDbContext.Add(new Users() { Name = "Rishi" }); // 手动创建Identity用户并处理密码哈希 var user = new ApplicationUser { UserName = model.Email, Email = model.Email, PhoneNumber = model.PhoneNumber }; var passwordHash = _userManager.PasswordHasher.HashPassword(user, model.Password); user.PasswordHash = passwordHash; applicationDbContext.Users.Add(user); // 批量保存所有变更(包括自定义表和AspNetUser表) await applicationDbContext.SaveChangesAsync(); var savedUser = await _userManager.FindByEmailAsync(model.Email); if (savedUser != null) { SaveEntity(savedUser, model); // 保存其他表数据 await applicationDbContext.SaveChangesAsync(); // throw new Exception(); // 测试回滚时可以取消注释 await dbTransaction.CommitAsync(); // 提交事务 } return Ok(); } catch (Exception ex) { await dbTransaction.RollbackAsync(); // 手动回滚事务 return BadRequest(new { Message = "注册失败:" + ex.Message }); } } }
问题根源解释
默认的_userManager.CreateAsync方法内部会自动调用DbContext.SaveChanges(),这个操作如果没有被纳入统一的事务上下文,就会直接将AspNetUser表的变更提交到数据库,而你手动创建的事务只覆盖了自己调用SaveChanges()的操作,最终导致事务不一致。
上面两种方案分别通过全局事务包裹和手动控制保存流程的方式,让所有数据库操作都处于同一个事务控制下,确保要么全部提交,要么全部回滚。
内容的提问来源于stack exchange,提问作者rishi kumar
相关产品推荐
相关产品推荐

