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

如何解决ASP.NET Core Web API中TransactionScope已完成的错误

问题原因与修复方案

错误“The current TransactionScope is already complete”的核心原因有两个:

  • 手动调用transaction.Dispose()提前终止了事务,后续代码(或框架内部)的数据库操作尝试使用已结束的事务
  • 登录操作SignInAsync被放在transaction.Complete()之后,若该操作触发EF Core查询,就会访问已完成的事务

具体修复步骤:

  1. 移除所有手动的transaction.Dispose()调用
    using语句会自动管理TransactionScope的生命周期,手动调用Dispose()会提前释放事务,导致后续数据库操作报错。

  2. 将登录操作移到事务范围外
    用户登录属于会话管理操作,和数据库事务无关,不需要包含在事务里。事务只需包裹用户创建、角色分配、BankUser插入这些数据库变更操作。

修改后的代码示例:

public async Task<Response<string>> RegisterUserAsync(string userId)
{
    var response = new Response<string>();
    using (var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
    {
        try
        {
            var userDetail = _dataAccess.GetSaffUserProfile(userId);
            adminAccess = _config.GetSection("DDMAdminCredentials").GetValue<string>("adminaccess");
            if (string.IsNullOrEmpty(userDetail.user_logon_name))
            {
                _logger.Error("Failed Authentication");
                response.Successful = false;
                response.StatusCode = (int)HttpStatusCode.BadRequest;
                response.Message = "Staff Record Not Found!";
                return response;
            }
            var user = new ApplicationUser()
            {
                UserName = userDetail.user_logon_name.ToLower().Trim(),
                Email = string.IsNullOrWhiteSpace(userDetail.email) ? null : userDetail.email.Trim().ToLower(),
                FirstName = string.IsNullOrWhiteSpace(userDetail.firstname) ? null : userDetail.firstname.Trim(),
                LastName = string.IsNullOrWhiteSpace(userDetail.lastname) ? null : userDetail.lastname.Trim(),
                MobileNumber = string.IsNullOrWhiteSpace(userDetail.mobile_phone) ? null : userDetail.mobile_phone.Trim(),
                CreatedAt = DateTime.Now
            };
            var result = await _userManager.CreateAsync(user, adminAccess);
            if (result.Succeeded)
            {
                // Insert User Role
                await _userManager.AddToRoleAsync(user, userRole);
                userBranchNo = userDetail.branch_code.TrimStart('0');
                var bankBranchId = _dbContext.BankBranches.Where(u => u.BranchNumber.ToString() == userBranchNo.ToString()).Select(m => m.Id).FirstOrDefault();
                var bankUser = new BankUser()
                {
                    UserId = user.Id,
                    BankBranchId = bankBranchId,
                    CreatedBy = "System"
                };
                await _unitOfWork.AdminUsers.InsertAsync(bankUser);
                await _unitOfWork.Save();

                response.StatusCode = (int)HttpStatusCode.Created;
                response.Successful = true;
                response.Data = user.Id;
                response.Message = "Bank User Created Successfully!";
                transaction.Complete();
                return response;
            }
            response.Message = GetErrors(result);
            response.StatusCode = (int)HttpStatusCode.BadRequest;
            response.Successful = false;
            return response;
        }
        catch (Exception ex)
        {
            response.Message = "An error occured :" + ex.Message;
            response.Successful = false;
            response.StatusCode = (int)HttpStatusCode.BadRequest;
            return response;
        }
    }
    // 登录操作移到事务范围外
    var createdUser = await _userManager.FindByIdAsync(response.Data);
    if(createdUser != null)
    {
        await _signInManager.SignInAsync(createdUser, isPersistent: false);
    }
    return response;
}

额外说明:

  • 事务完成后重新通过FindByIdAsync获取用户,是因为原user对象可能在事务结束后脱离了EF上下文,确保登录时使用的是有效实体
  • 如果SignInAsync不需要查询数据库(比如直接使用传入的user对象),也可以直接在事务完成后调用,但重新查询更稳妥

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 14:55:20