2016-06-28 79 views
0

在我的一个应用程序中,我重写了Asp Core Identity UserManager的CreateAsync,除了在UserStore中创建新用户之外 - 在单独的统计表中创建一个新行不同的dbcontext)。问题是,我希望这些操作都在事务内部被触发,这样如果一个操作失败 - 另一个操作不会提交。下面的代码:与ASP.NET Core 1.0 Identity UserManager交易

public override async Task<IdentityResult> CreateAsync(TUser user, string password) 
    { 
     // We need to use transactions here.    
      var result = await base.CreateAsync(user, password); 

      if (result.Succeeded) 
      { 
       var appUser = user as IdentityUser; 

       if (appUser != null) 
       { 
        // create user stats. 
        var userStats = new UserStats() 
        { 
         ActionsCount = 0, 
         EventsCount = 0, 
         FollowersCount = 0, 
         ProjectsCount = 0, 
         UserId = appUser.Id 
        }; 

        _ctx.UserStats.Add(userStats); 
        await _ctx.SaveChangesAsync(); 
       } 
      }  
      return result; 
    } 

事情是,我不知道如何建立这样一个交易,因为它似乎TransactionScope的是不是对.NET核心的一部分,但和获得目前选择的DbContext为基数(?)。 CreateAsync()与HttpContext.GetOwinContext()不起作用,因为HttpContext似乎缺少这种方法(引用Microsoft.Owin.Host.SystemWeb或Microsoft.AspNet.WebApi.Owin作为暗示在其他堆栈溢出答案不会做 - 两者都不兼容.netcore)。任何帮助?

回答

2

首先你需要设置你使用的是有身份的DbContext与范围的一生:

 services.AddDbContext<MyDbContext>(ServiceLifetime.Scoped); // this is the important bit 

     services.AddIdentity<User, Role>(options => 
     { 
     }) 
     .AddEntityFrameworkStores<MyDbContext, int>() 
     .AddDefaultTokenProviders(); 

然后,当你需要创建你做的交易如下:

 using (var transaction = await _myDbContext.Database.BeginTransactionAsync()) 
     { 
      var result = await _userManager.CreateAsync(newUser, password); 

      try 
      { 
       if (result.Succeeded) 
       { 
        DBItem newItem = new DBItem(); 
        _myDbContext.Add(newItem); 

        await _myDbContext.SaveChangesAsync(); 
        transaction.Commit(); 
       } 
      } 
      catch (Exception e) 
      { 
       transaction.Rollback(); 
      } 
     } 
+0

伟大的东西!感谢你这个方向,似乎它可能是一条路,如果我只能配置Scoped生命周期,似乎在EF 1.0.0-rc2-final中,AddDbContext没有采用ServiceLifetime的方法,也没有允许您为DbContext设置Transient/Scoped生命周期,并且我无法升级到1.0.0,因为它会中断我的应用程序,因此必须等待以查看它是否有效。 – RRob

+0

我已经注册了两个上下文,例如: – RRob

+0

我已经注册了两个上下文,例如: \t services.AddScoped (); services.AddScoped (); 但仍然,等待base.CreateAsync(用户,密码);不关心交易范围。 – RRob

0

我相信下面的是一个正确的方向:

using (var transaction = _context.Database.BeginTransaction()) 
{ 

} 
+0

这将是一个很好的方向,但我该如何获得cur租用上下文使用UserManager内的Base.CreateAsync(用户,密码)在第一位? – RRob

+0

我目前看到的唯一解决方案是检索当前作用域(由DI注入)DbContext,注册为services.AddIdentity ... AddEntityFrameworkStores through HttpContext.GetOwinContext()。获取()如下所示:http:// stackoverflow.com/questions/32858014/how-to-create-transaction-with-asp-net-identity,但是无法找到一种方法来使HttpContext有GetOwinContext()方法在Asp Core 1 – RRob