How to send data in multiple db tables? - asp.net-mvc-4

I have created web api 2 project which created a local db in which there was a table "AspNetUser". I have merged those tables with my own db. In my database I have a table "Employee Information" that will store all information of the employee except his Email,Password and UserName and all the other information will be stored in "Employee Information" table.
This is the pre-written code to register user:
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var user = new ApplicationUser() { UserName = model.UserName, Email = model.Email};
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
var currentUser = UserManager.FindByName(user.UserName);
var roleresult = UserManager.AddToRole(currentUser.Id, model.SelectedRole);
}
else if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
And This is my own logic to register User:
[ResponseType(typeof(EmployeeInformation))]
[ActionName("EmployeeInfo")]
[DeflateCompression]
public IHttpActionResult PostEmployeeInformation(EmployeeInformation EmployeeInfo)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.EmployeeInformations.Add(EmployeeInfo);
db.SaveChanges();
So how can I Store Email,password and Username in "AspNetUser" table and all the other information(name,fathername,dob etc) in "EmployeeInformation" table.
Thanks.

Simply add relation between ApplicationUser and EmployeeInformation entities:
public class ApplicationUser: IdentityUser
{
// other properties
public int EmployeeInformationID {get;set;}
public virtual EmployeeInformation EmployeeInformation {get;set;}
}
Do same for EmployeeInformation class
public class EmployeeInformation
{
// other properties
public string UserID {get;set;}
public virtual ApplicationUser User {get;set;}
}
Now you have seprate class for user's extra information for example you could write:
public IHttpActionResult PostEmployeeInformation(EmployeeInformation employeeInfo)
{
employeeInfo.UserID="your desired user id, current user id for example";
db.EmployeeInformations.Add(employeeInfo);
db.SaveChanges();
}

Related

How can i commit in identity aspnetusers table and another table in one transaction

i have two tables one is identity table aspnetuser and other is the user table that i have created now one of the column in aspnetuser is identity column autogenerated and this is the foreign key in aspnetuser table and primary key in user table ultimately creating one-one relationship.
now i have this need where i want to insert in these two tables at the same time so if after creating record in aspnetuser succeeds but creating record in users table fails i need to rollback the changes.
how can i achieve this? because for now await _userManager.CreateAsync(user, Input.Password);
this piece of code enters record in aspnetuser table as soon as its called...
i found something similar here How to create transaction with asp.net identity? but can't get my head around it as in my case aspnetuser table has a U_ID column which is identity column generated by db and i need to get its value to create a new record in user table
is it even possible?
here's the diagram
one-one relation
and here's the application user
public class ApplicationUser : IdentityUser
{
[PersonalData]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int U_ID { get; set; }
}
UPDATE
as told by #Zhi Lv i tried this
returnUrl ??= Url.Content("~/");
var result = false;
var errorlist = new List<IdentityError>();
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
var user = new ApplicationUser();
if (ModelState.IsValid)
{
using (var transaction = _dbcontext.Database.BeginTransaction())
{
try
{
Guid guid = Guid.NewGuid();
ShortGuid sguid1 = guid;
//insert user to Users table.
var customeruser = new OnlineEarning.Core.DataModel.Models.User()
{
Name = Input.UserName,
Password = Input.Password,
Email = Input.Email,
UserRefNo = sguid1,
EasyPaisaNoJazzCashNo = "2214457896",
PhoneNo = "2214457896",
City = "Rwp",
};
_dbcontext.Users.Add(customeruser);
_dbcontext.SaveChanges();
//get the latest user id.
var u_id = customeruser.Id;
//
user = new ApplicationUser { UserName = Input.Email, Email = Input.Email, U_ID = u_id };
var saveresult = await _userManager.CreateAsync(user, Input.Password);
if (saveresult.Succeeded)
result = true;
else
errorlist = saveresult.Errors.ToList();
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
}
}
if (result)
{
//do something
}
foreach (var error in errorlist)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
// If we got this far, something failed, redisplay form
return Page();
but now i am getting this exception 'Execution TImeout expired'
UPDATE 2
now i am able to create a transaction and enter records in both table in single transaction with below code
try
{
returnUrl ??= Url.Content("~/");
var result = false;
var errorlist = new List<IdentityError>();
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
var user = new ApplicationUser();
if (ModelState.IsValid)
{
using (TransactionScope transaction = new TransactionScope(System.Transactions.TransactionScopeAsyncFlowOption.Enabled))
{
try
{
Guid guid = Guid.NewGuid();
ShortGuid sguid1 = guid;
//insert user to Users table.
var customeruser = new OnlineEarning.Core.DataModel.Models.User()
{
Name = Input.UserName,
Password = Input.Password,
Email = Input.Email,
UserRefNo = sguid1,
EasyPaisaNoJazzCashNo = "01224457854",
PhoneNo = "01224457854",
City = "Rwp",
};
_dbcontext.Users.Add(customeruser);
_dbcontext.SaveChanges();
//get the latest user id.
var u_id = customeruser.Id;
user = new ApplicationUser { UserName = Input.Email, Email = Input.Email, U_ID = u_id };
var saveresult = await _userManager.CreateAsync(user, Input.Password);
if (saveresult.Succeeded)
{
result = true;
var uservs = await _userManager.FindByEmailAsync(Input.Email);
await _signInManager.SignInAsync(user, isPersistent: false);
var userv = await _userManager.FindByEmailAsync(Input.Email);
}
else
errorlist = saveresult.Errors.ToList();
transaction.Complete();
}
catch (Exception ex)
{
transaction.Dispose();
ModelState.AddModelError(string.Empty, ex.InnerException.Message.ToString());
}
}
if (result)
{
//do something
}
foreach (var error in errorlist)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
// If we got this far, something failed, redisplay form
return Page();
}
catch(Exception ex)
{
return Page();
}
but during debugging i found out i was unable to read or write to both the tables in sql server when transaction was started in debugging..now my question is what if two users try to register at the same time?will only one of them be allowed and other one will get exception?if yes then what to do in this kind of situation...offcourse transaction is must cannot avoid it otherwise data would be inconsistent
As far as I know, only one column per table can be configured as Identity, so, in the ApplicationUser class, since it inheriting from the IdentityUser (it already contains the identity column), even you configure the U_ID as Identity, the database will not generate a value when a row is inserted. Besides, according to the diagram, it seems that you want to configure one-to-one relationship between the aspnetusers table and Users table, if that is the case, I suggest you could try to set the Identity column in the Users table, and use the following code to configure relationships:
User.cs:
public class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int U_ID { get; set; }
public string Name { get; set; }
public string Password { get; set; }
public string PhoneNo { get; set; }
public string Email { get; set; }
public ApplicationUser ApplicationUser { get; set; }
}
ApplicationUser.cs:
public class ApplicationUser:IdentityUser
{
[PersonalData]
public int U_ID { get; set; }
[ForeignKey("U_ID")]
public User User { get; set; }
}
ApplicationDbContext.cs:
public class ApplicationDbContext : IdentityDbContext
{
public DbSet<ApplicationUser> ApplicationUsers { get; set; }
#pragma warning disable CS0114 // Member hides inherited member; missing override keyword
public DbSet<User> Users { get; set; }
#pragma warning restore CS0114 // Member hides inherited member; missing override keyword
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
}
Then, when register the user, you could refer to the following code to use transaction and insert data.
[AllowAnonymous]
public class RegisterModel : PageModel
{
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly UserManager<ApplicationUser> _userManager;
private readonly ApplicationDbContext _context;
public RegisterModel( UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager, ApplicationDbContext context )
{
_userManager = userManager;
_signInManager = signInManager;
_context = context;
}
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
var result = false;
var errorlist = new List<IdentityError>();
var user = new ApplicationUser();
if (ModelState.IsValid)
{
using (var transaction = _context.Database.BeginTransaction())
{
try
{
//insert user to Users table.
var customeruser = new User() { PhoneNo = "12345678", Name = "Tom", Password = "Password01", Email = "tom#hotmail.com" };
_context.Users.Add(customeruser);
_context.SaveChanges();
//get the latest user id.
var u_id = customeruser.U_ID;
//
user = new ApplicationUser { UserName = Input.Email, Email = Input.Email, U_ID = u_id };
var saveresult = await _userManager.CreateAsync(user, Input.Password);
if (saveresult.Succeeded)
result = true;
else
errorlist = saveresult.Errors.ToList();
transaction.Commit();
}
catch (Exception)
{
transaction.Rollback();
}
}
if (result)
{
//do something
}
foreach (var error in errorlist)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
// If we got this far, something failed, redisplay form
return Page();
}
}
The result like this:
Reference:
Entity Framework Core Transaction
Using Transactions
One-to-One Relationship Conventions in Entity Framework Core
[Update]
In your scenario, you could insert the AspnetUser first, then get the U_ID and insert a new item into the Users table, please try to change the code as below:
var result = false;
var errorlist = new List<IdentityError>();
var user = new ApplicationUser();
if (ModelState.IsValid)
{
using (var transaction = _context.Database.BeginTransaction())
{
try
{
user = new ApplicationUser { UserName = Input.Email, Email = Input.Email };
var saveresult = await _userManager.CreateAsync(user, Input.Password);
if (saveresult.Succeeded)
{
result = true;
//get the U_ID
var userid = user.U_ID;
//use the U_ID to create user.
var customeruser = new User() { U_ID = userid, PhoneNo = "12345678", Name = "Tom", Password = "Password01", Email = "tom#hotmail.com" };
_context.Users.Add(customeruser);
_context.SaveChanges();
}
else{
errorlist = saveresult.Errors.ToList();
}
transaction.Commit();
}
catch (Exception)
{
transaction.Rollback();
}
}
if (result)
{
//do something
}
foreach (var error in errorlist)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}

.Net Core IdentityServer using custom table for ApplicationUser

We are implementing identityserver authentication for our .net core api project. I have implemented identityserver infrastructure which created AspNetUsers,AspNetUserRoles etc. tables. The users are inserted in aspnetusers table. I want to use our member table instead of aspnetusers table. How can I do that?
public class ApplicationUser : IdentityUser
{
[Required]
[MaxLength(200)]
public String Name { get; set; }
}
[HttpPost]
[Route("token")]
public async Task<IActionResult> CreateToken([FromBody] LoginModel loginModel)
{
if (ModelState.IsValid)
{
var loginResult = await signInManager.PasswordSignInAsync(loginModel.Username, loginModel.Password, isPersistent: false, lockoutOnFailure: false);
if (!loginResult.Succeeded)
{
return BadRequest();
}
var user = await userManager.FindByNameAsync(loginModel.Username);
Login();
return Ok(GetToken(user));
}
return BadRequest(ModelState);
}

How to get all user with the associate organization?

Its keep a week that I'm trying to figure this out. I hope to get help from community. Here is a scenario:
I have a entity class called "Company". One company has many users (One-To-Many)
public class User : IdentityUser<int>
{
public User()
{
Company = new Company();
}
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime CreatedDate { get; set; } = DateTime.Now;
public virtual ICollection<UserRole> UserRoles { get; set; }
public virtual Company Company { get; set; }
public int CompanyId { get; set; }
}
I also have a company entity like so.
public class Company
{
public Company()
{
Users = new List<User>();
}
public int CompanyId { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "Company Name")]
public string CompanyName { get; set; }
public virtual List<User> Users { get; set; }
}
Now, I can add new company but I cannot add users.
Here is my Controller/Create
[HttpGet]
public IActionResult Create(int companyId)
{
ViewData["UserList"] = new SelectList(_context.Companies, "CompanyId", "CompanyName", companyId);
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(RegisterViewModel viewModel)
{
if (ModelState.IsValid)
{
var user = await _userManager.FindByEmailAsync(viewModel.UserName);
if (user == null)
{
user = new User
{
UserName = viewModel.UserName,
FirstName = viewModel.FirstName,
LastName = viewModel.LastName,
Email = viewModel.UserName,
PhoneNumber = viewModel.PhoneNumber
};
var result = await _userManager.CreateAsync(user, viewModel.Password);
if (result.Succeeded)
{
RedirectToAction(nameof(Index));
}
else
{
foreach (var error in result.Errors)
{
ModelState.AddModelError("", error.Description);
}
return View();
}
}
return View("Success");
}
ViewData["CompanyId"] = new SelectList(_context.Companies, "Id", "Id", viewModel.CompanyId);
return View();
}
When i run the program and enter data in a POST/Form,
if (ModelState.IsValid)
{
Model.IsValid is always return false. and it ask to enter Company information which i don't want it because i already have company data. I all was trying to do is have Foreign Id linked with user.
Since Identity already have built in function like
var users = await _userManager.GetUserAsync(viewModel.UserName);
How to i also query like Include in GetUserAsync method?

How to register a use with role in .net core?

I wants to create a new user with role. I'm using entity migration. so i get the all default tables. Without roles I'm able to register a new user but when i add the roles drop down I'm facing a error Cannot convert from string to ourproject.entitites.user
Please help and teach me where i did the mistake. I'm new to .net core technology.
I'm facing a problem with user.Id
await _userManager.AddToRoleAsync(user.Id, model.UserRoles);
ControllerCode:
[HttpPost, ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterUserModel model)
{
if (ModelState.IsValid)
{
var user = new User { UserName = model.Username, Email = model.Email,
PhoneNumber = model.PhoneNumber };
//var phoneNo = new User { PhoneNumber = model.PhoneNumber };
var createResult = await _userManager.CreateAsync(user, model.Password);
if (createResult.Succeeded)
{
await _userManager.AddToRoleAsync(user.Id, model.UserRoles);
return RedirectToAction("Details", "Home");
}
else
{
ViewBag.Name = new SelectList(_Context.Roles.Where(u => !u.Name.Contains("Admin"))
.ToList(), "Name", "Name");
foreach (var error in createResult.Errors)
{
ModelState.AddModelError("", error.Description);
}
}
}
return View();
}
Registermodel Code:
public class RegisterUserModel
{
[Required,MaxLength(256)]
public string Username { get; set; }
[Required, DataType(DataType.Password)]
public string Password { get; set; }
[Required, DataType(DataType.Password), Compare(nameof(Password))]
public string ConfirmPassword { get; set; }
[Required, DataType(DataType.EmailAddress),MaxLength(256)]
public string Email { get; set; }
[Required,DataType(DataType.PhoneNumber)]
public string PhoneNumber { get; set; }
[Display(Name ="UserRoles")]
public string UserRoles { get; set; }
}
User Entity Code:
using Microsoft.AspNetCore.Identity;
namespace OurProject.Entities
{
public class User : IdentityUser
{
}
}
Here is a functional code for .net core 2.0. In AddToRoleAsync method I am sending user object itself.
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
string roleName = "Manager";
var isExistRole = await this._roleManager.RoleExistsAsync(roleName);
if (!isExistRole)
{
await this._roleManager.CreateAsync(
new IdentityRole
{
Id = Guid.NewGuid().ToString(),
Name = roleName
});
}
await _userManager.AddToRoleAsync(user, roleName);
return RedirectToLocal(returnUrl);
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}

ASP.NET Core Identity Extend Not Saving

I'm attempting to extend the ASP.NET Identity. I feel like I have most of the parts. The model and user objects all properly populate. However, when I check the database for the new record inserted via the CreateAsync function, the new fields are all NULL. What am I missing?
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email, FirstName = model.FirstName, LastName = model.LastName
, Organization = model.Organization };
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
_logger.LogInformation("User created a new account with password.");
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.EmailConfirmationLink(user.Id.ToString(), code, Request.Scheme);
await _emailSender.SendEmailConfirmationAsync(model.Email, callbackUrl);
await _signInManager.SignInAsync(user, isPersistent: false);
_logger.LogInformation("User created a new account with password.");
return RedirectToLocal(returnUrl);
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
// Signin settings
options.SignIn.RequireConfirmedEmail = false;
options.SignIn.RequireConfirmedPhoneNumber = false;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
public class ApplicationUser : IdentityUser
{
public String FirstName;
public String LastName;
public String Organization;
}
You need to use auto-implemented properties in your ApplicationUser class instead of just using public fields. That might be the problem.
public class ApplicationUser : IdentityUser
{
public String FirstName { get; set; }
public String LastName { get; set; }
public String Organization { get; set; }
}