[英]How to create transaction with asp.net identity?
我正在注冊,我要求 5 件事:
全名、電子郵件 ID、密碼、聯系電話、性別
現在,我使用注冊方法存儲電子郵件 ID 和密碼,並在以下兩個鏈接中給出:
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
using var context = new MyEntities())
{
using (var transaction = context.Database.BeginTransaction())
{
try
{
var DataModel = new UserMaster();
DataModel.Gender = model.Gender.ToString();
DataModel.Name = string.Empty;
var result = await UserManager.CreateAsync(user, model.Password);//Doing entry in AspnetUser even if transaction fails
if (result.Succeeded)
{
await this.UserManager.AddToRoleAsync(user.Id, model.Role.ToString());
this.AddUser(DataModel, context);
transaction.Commit();
return View("DisplayEmail");
}
AddErrors(result);
}
catch (Exception ex)
{
transaction.Rollback();
return null;
}
}
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
public int AddUser(UserMaster _addUser, MyEntities _context)
{
_context.UserMaster.Add(_addUser);
_context.SaveChanges();
return 0;
}
現在有了以下兩行:
var result = await UserManager.CreateAsync(user, model.Password);//entry is done in AspnetUsers table.
await this.UserManager.AddToRoleAsync(user.Id, model.Role.ToString());//entry is done is Aspnetuserrole table
現在這個 Fullname,contactno,gender 我在另一個表中是UserMaster 。
因此,當我提交注冊表時,我會將這些詳細信息保存在UserMaster 和 AspnetUsers,AspnetUserinrole 表中。
但是考慮在 UserMaster 中保存記錄時是否出現任何問題,那么我也不想在 Aspnetuser 和 Aspnetuserinrole 中保存條目。
我想創建一個事務,如果在任何表中保存任何記錄期間發生任何問題,我將回滾,即不應在 AspnetUser、AspnetUserinRole 和 userMaster 中完成任何條目。
只有在這 3 個表中保存記錄沒有問題時,記錄才能成功保存,否則事務應該是角色返回。
我正在使用 Microsoft.AspNet.Identity 進行登錄、注冊、角色管理和其他操作,並遵循本教程:
但是由於 await UserManager.CreateAsync 和 UserManager.AddToRoleAsync 方法是內置方法,我將如何同步它以與實體框架一起使用。
那么有人可以指導我如何創建這樣的交易或任何可以解決這個問題的東西嗎?
身份配置:
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = true,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
// Configure user lockout defaults
manager.UserLockoutEnabledByDefault = true;
manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
manager.MaxFailedAccessAttemptsBeforeLockout = 5;
// Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user
// You can write your own provider and plug it in here.
manager.RegisterTwoFactorProvider("Phone Code", new PhoneNumberTokenProvider<ApplicationUser>
{
MessageFormat = "Your security code is {0}"
});
manager.RegisterTwoFactorProvider("Email Code", new EmailTokenProvider<ApplicationUser>
{
Subject = "Security Code",
BodyFormat = "Your security code is {0}"
});
manager.EmailService = new EmailService();
manager.SmsService = new SmsService();
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider =
new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
return manager;
}
}
// Configure the application sign-in manager which is used in this application.
public class ApplicationSignInManager : SignInManager<ApplicationUser, string>
{
public ApplicationSignInManager(ApplicationUserManager userManager, IAuthenticationManager authenticationManager)
: base(userManager, authenticationManager)
{
}
public override Task<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user)
{
return user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);
}
public static ApplicationSignInManager Create(IdentityFactoryOptions<ApplicationSignInManager> options, IOwinContext context)
{
return new ApplicationSignInManager(context.GetUserManager<ApplicationUserManager>(), context.Authentication);
}
}
您不應創建新的 db 上下文,而應使用現有的上下文。
var context = Request.GetOwinContext().Get<MyEntities>()
如果您使用默認實現,它是按請求創建的。
app.CreatePerOwinContext(ApplicationDbContext.Create);
更新:
好的,由於您使用了兩個不同的上下文,因此您的代碼將如下所示:
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var appDbContext = HttpContext.GetOwinContext().Get<ApplicationDbContext>();
using( var context = new MyEntities())
using (var transaction = appDbContext.Database.BeginTransaction())
{
try
{
var DataModel = new UserMaster();
DataModel.Gender = model.Gender.ToString();
DataModel.Name = string.Empty;
// Doing entry in AspnetUser even if transaction fails
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await this.UserManager.AddToRoleAsync(user.Id, model.Role.ToString());
this.AddUser(DataModel, context);
transaction.Commit();
return View("DisplayEmail");
}
AddErrors(result);
}
catch (Exception ex)
{
transaction.Rollback();
return null;
}
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
public int AddUser(UserMaster _addUser, MyEntities _context)
{
_context.UserMaster.Add(_addUser);
_context.SaveChanges();
return 0;
}
此處, appDbContext
與UserManager
使用的上下文相同。
您可以使用TransactionScope類解決它:
using (TransactionScope scope = new TransactionScope())
{
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await this.UserManager.AddToRoleAsync(user.Id, model.Role.ToString());
string callbackUrl = await SendEmailConfirmationTokenAsync(user.Id, "Confirm your account");
return View("DisplayEmail");
}
scope.Complete();
}
因此,這兩個操作都將在一個事務中完成,如果未調用Comlete
方法,則這兩個操作都將被取消(回滾)。
如果你只想用EF(沒有TransactionScope)解決它,你需要重構你的代碼。 我不知道類UserManager
和方法CreateAsync
和AddToRoleAsync
,但我猜他們為每個操作創建了新的 DBContext 。 因此,首先,對於所有事務性操作,您都需要一個 DBContext(用於 EF 解決方案)。 如果您添加此方法,我將根據 EF 解決方案修改我的答案。
當我使用此方法時,支持替代對我有用: TransactionScope(TransactionScopeAsyncFlowOption.Enabled)
來源: https : //docs.microsoft.com/en-us/ef/ef6/saving/transactions
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.