【问题标题】:Transactions with ASP.NET Identity UserManager与 ASP.NET Identity UserManager 的事务
【发布时间】:2016-08-06 18:49:55
【问题描述】:

我正在尝试更新用户。

AppUserManager appUserManager = HttpContext.GetOwinContext().GetUserManager<AppUserManager>();

AppUser member = await appUserManager.FindByIdAsync(User.Identity.GetUserId());

member.HasScheduledChanges = true;

IdentityResult identityResult = appUserManager.Update(member);

如果对 Web API 的后续调用失败,我需要回滚对用户的任何更改。我知道交易,像这样:

using (var context = HttpContext.GetOwinContext().Get<EFDbContext>())
 {
    using (var dbContextTransaction = context.Database.BeginTransaction())
    {      
        try
        {   
            // Changes

            member.HasScheduledChanges = true;

            // Would this be transactional?
            IdentityResult identityResult = appUserManager.Update(member);               

            context.SaveChanges();

            dbContextTransaction.Commit();
        }
        catch //(Exception ex)
        {

            // dbContextTransaction.Rollback(); no need to call this manually.
        }
    }
}

但是在 try 块中使用 AppUserManager 完成的操作是否是事务性的?此外,他们是否使用相同的 EFDbContext 实例?换句话说,我不知道第二个代码示例开头的 var context 是否会被 try 块中的 appUserManager“Update”方法调用使用。

另外,AppUserManager 是这样创建的:

public static AppUserManager Create(IdentityFactoryOptions<AppUserManager> options, IOwinContext context)
{           

    EFDbContext db = context.Get<EFDbContext>();

    AppUserManager manager = new AppUserManager(new UserStore<AppUser>(db));

    // etc.

    return manager;
}

【问题讨论】:

    标签: c# asp.net transactions asp.net-identity usermanager


    【解决方案1】:

    EFDbContext 在您的示例中是相同的 - 在这两种情况下,您都可以从 OWIN 上下文中解决它们,因此这不是问题。但是,Identity 是以与存储无关的方式编写的,这意味着存储机制可以被非 SQL Server 替换。这要求AppUserManager 内部缺少事务。所以你需要创建自己的。

    我经常在我的生产应用程序中使用var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)(仅具有更多架构):

    using(var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
    {
        try
        {
            AppUserManager appUserManager = HttpContext.GetOwinContext().GetUserManager<AppUserManager>();
    
            AppUser member = await appUserManager.FindByIdAsync(User.Identity.GetUserId());
    
            member.HasScheduledChanges = true;
    
            IdentityResult identityResult = appUserManager.Update(member);
            scope.Complete();
        }
        catch (Exception ex)
        {
            scope.Dispose();
            throw;
        }
    }
    

    【讨论】:

    • 谢谢!我的第一个想法是直接使用支持事务的 dbContext 来操作 AspNetUsers 表,但我认为这是不可能的。我认为必须使用 UserManager 来更新身份系统中的用户,没有别的办法吗?
    • 是的,您可以直接通过dbContext 操作用户记录。这就是AppUserManager 所做的,只是它增加了一点验证
    • 你是 Owin 和 Identity 方面的专家,也许你可以看看这个:stackoverflow.com/questions/43037450/…
    • scope.Dispose() 在您的异常处理程序中是完全多余的。
    • @trailmax 为了扩展 Michaels 的评论,using 语句最终将内容包装在 try 中并调用 scope.dispose()。捕获并重新抛出异常没有任何作用,只是稍微减慢了失败的速度,因为它实际上必须捕获异常。
    【解决方案2】:

    使用asp.net身份UserManager进行事务提交/回滚的完整解决方案

    var appDbContext = HttpContext.GetOwinContext().Get<ApplicationDbContext>();
    using (var identitydbContextTransaction = appDbContext.Database.BeginTransaction())
    {
       try
       {
           var result = await UserManager.CreateAsync(user, "password");
           if (result.Succeeded)
           {
             var userinfo = await UserManager.FindByNameAsync("Email");
             var userId = user.Id;
             await UserManager.AddToRoleAsync(userId, "rolename");
    
             identitydbContextTransaction.Commit();
           }
      }
      catch (Exception)
      {
            identitydbContextTransaction.Rollback();
      }
    }
    

    它可以帮助你,使用 asp.net 身份 UserManager 进行交易。但它对我有用,如果事务中发生任何错误,它将回滚所有事务。

    【讨论】:

    • 这个答案解决了我的问题,我不想使用“事务范围”,我不得不添加对 OWIN 的引用“使用 Microsoft.AspNet.Identity.Owin;”
    • 但是在控制器上这样做是正确的方法吗?有事务的控制器?
    • 有趣的是,这样做而不是使用公认的答案有什么好处。我想做几乎相同的事情。
    • 对于用户来说,在现有的 DbContext 中自己启动和完成事务是一种更简单的方法——允许在同一个事务中组合多个操作,因此要么全部提交,要么全部回滚。它还允许用户更轻松地为事务指定隔离级别。
    • 我可能错了,但这里的回滚不是多余的吗?如果发生异常,事务将被处理并且更改丢失。
    猜你喜欢
    • 2019-07-21
    • 2015-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-29
    • 2020-10-29
    • 2016-11-09
    • 1970-01-01
    相关资源
    最近更新 更多