与ASP.NET Core 1.0 Identity UserManager的事务

RRo*_*Rob 1 .net asp.net asp.net-identity

在我的一个应用程序中,除了在UserStore中创建新用户外,我还重写了Asp Core Identity UserManager的CreateAsync-在单独的统计信息表中(在不同的dbcontext上)创建新行。问题是,我希望将这两个操作都在事务内触发,这样,如果一个操作失败-另一个则不提交。这是代码:

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;
    }
Run Code Online (Sandbox Code Playgroud)

事情是,我不知道如何设置这样的事务,因为TransactionScope似乎还不是.Net Core的一部分(?),并且当前使用HttpContext.GetOwinContext()获取base.CreateAsync()的当前作用域DbContext并不由于HttpContext似乎缺少此方法,因此无法工作(引用其他堆栈溢出答案中所暗示的Microsoft.Owin.Host.SystemWeb或Microsoft.AspNet.WebApi.Owin都行不通-两者均与.netcore不兼容)。有什么帮助吗?

kiw*_*jus 5

首先,您需要使用具有一定范围生存期的身份来设置要使用的dbcontext:

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

        services.AddIdentity<User, Role>(options =>
        {
        })
        .AddEntityFrameworkStores<MyDbContext, int>()
        .AddDefaultTokenProviders();
Run Code Online (Sandbox Code Playgroud)

然后,当您需要创建事务时,请执行以下操作:

        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();
            }
        }
Run Code Online (Sandbox Code Playgroud)

  • catch 块中的“transaction.Rollback()”不是必需的,因为它会在离开 using 语句时自动调用,并且之前没有调用“transaction.Commit()”。 (2认同)