public async Task <LoginUserTxnPayload> LoginUser( LoginUserTxnInput input, [Service] IConfiguration configuration, [Service] UserManager <IdentityUser> userManager, [Service] SignInManager <IdentityUser> signInManager, [Service] ApplicationDbContext contextMVC) { return(await new LoginUserTxn().Execute( input: input, configuration: configuration, userManager: userManager, signInManager: signInManager, contextMVC: contextMVC, autoCommit: true )); }
public async Task <LoginUserTxnPayload> Execute( LoginUserTxnInput input, IConfiguration configuration, UserManager <IdentityUser> userManager, SignInManager <IdentityUser> signInManager, ApplicationDbContext contextMVC, bool autoCommit) { LoginUserTxnPayload _payload = new LoginUserTxnPayload(); //***** Declare variables and messages string errorMessage = "LoginUserTxn***LOGIN_FAIL"; string okMessage = "LoginUserTxn***LOGIN_PASS"; string errorMessageExceptionCode = "LoginUserTxn***TXN_EXCEPTION"; string errorMessageException = "TXN_EXCEPTION"; // Error handling bool error = false; // To Handle Only One Error try { // DBContext by convention is a UnitOfWork, track changes and commits when SaveChanges is called // Multithreading issue: so if we use only one DBContext, it will track all entities (_context.Customer.Add) and commit them when SaveChanges is called, // No Matter what transactions or client calls SaveChanges. // Note: Rollback will not remove the entities from the tracker in the context. so better dispose it. //***** Make The Validations - Be careful : Concurrency. Same name can be saved multiple times if called at the exact same time. Better have an alternate database constraint if (!error) { // To check later - RefreshToken // https://stackoverflow.com/questions/53659247/using-aspnetusertokens-table-to-store-refresh-token-in-asp-net-core-web-api var result = await signInManager.PasswordSignInAsync(userName : input.Email, password : input.Password, isPersistent : false, lockoutOnFailure : false); if (!result.Succeeded) { _payload.PayloadResult = PayloadResult.ResultBad(Messages: new List <MessageItem>() { new MessageItem { Code = errorMessage, Message = errorMessage, Detail = "" } }); return(_payload); } var user = await signInManager.UserManager.FindByEmailAsync(input.Email); if (user == null) { _payload.PayloadResult = PayloadResult.ResultBad(Messages: new List <MessageItem>() { new MessageItem { Code = errorMessage, Message = errorMessage, Detail = "" } }); return(_payload); } // Get the UserApp var userApp = await contextMVC.UserApp.Where(x => x.IdentityId == user.Id).FirstOrDefaultAsync(); if (userApp == null) { _payload.PayloadResult = PayloadResult.ResultBad(Messages: new List <MessageItem>() { new MessageItem { Code = errorMessage, Message = errorMessage, Detail = "" } }); return(_payload); } //***** Save and Commit to the Database (Atomic because is same Context DB) if (!error && autoCommit) { await contextMVC.SaveChangesAsync(); // Call it only once so do all other operations first } //***** Confirm the Result (Pass | Fail) If gets to here there are not errors then return the new data from database _payload.PayloadResult = PayloadResult.ResultGood(Messages: new List <MessageItem> { new MessageItem { Code = okMessage, Message = okMessage, Detail = "" } }); _payload.JWTInfo = await this.CreateTokenAsync(user, userApp, configuration, userManager); }// if (!error) } catch (Exception ex) // Main try { System.Diagnostics.Debug.WriteLine("Error: " + ex.Message); string innerError = (ex.InnerException != null) ? ex.InnerException.Message : ""; System.Diagnostics.Debug.WriteLine("Error Inner: " + innerError); _payload = new LoginUserTxnPayload { PayloadResult = PayloadResult.ResultBad(Messages: new List <MessageItem> { new MessageItem { Code = errorMessageExceptionCode, Message = errorMessageException, Detail = ex.Message } }) }; // Restart variable to avoid returning any already saved data } finally { // Save Logs if needed } return(_payload); }