I understand that ASP.NET MVC creates a default table "AspNetUser" for storing users information during registration. How do I get Some of those data such as "Username" and store it in a seperate table during the registration process.
Am trying to get the "username" supplied by the user which is by default stored in the "AspNetUser Table" and store it in the "Student Table" also during the registration process
Register action
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
StudentEntities db = new StudentEntities();
var student = new Student
{
Name = model.Username
};
db.Student.Add(Student);
db.SaveChanges();
var user = new ApplicationUser() { UserName = model.UserName };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInAsync(user, isPersistent: false);
return RedirectToAction("Welcome", "Home");
}
else
{
AddErrors(result);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
This doesn't seem to work
This doesn't seem to work
StudentEntities db = new StudentEntities();
var student = new Student
{
Name = model.Username
};
db.Student.Add(Student);
db.SaveChanges();
If you are using MVC5, it means you are using identity2. So It is better to use that to get user details. The best approach is doing this:
Add the following using statement.
using Microsoft.AspNet.Identity;
You can now get more methods from the HttpContext.User.Identity.
var UserName = User.Identity.GetUserName();
var UserId = User.Identity.GetUserId();
Be noted that identity usually uses email as username. But you can change it anyway.
Related
I have a strange problem with ExternalLoginCallback method. I am logging some information in the log and what is interesting Email is correct, but then userId is incorrect and it belongs to another user who was logged previously.
I.e. some UserA is logged into the system and now UserB wants to log into the system in another window. I am expecting that in new window UserB will be logged in and overwrite cookies, so if I refresh first window it will show UserB, but somehow that is not happening and in second window it shows UserA.
Here is the code:
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{
return RedirectToAction("Login");
}
EventLogManager.LogWarning(loginInfo.Email);
var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: true);
switch (result)
{
case SignInStatus.Success:
{
var userId = SignInManager.AuthenticationManager.AuthenticationResponseGrant.Identity.GetUserId();
EventLogManager.LogWarning(userId);
...
EDIT
I think I should add more clarifications. There is some action which is being called from third party - Shopify. It looks like:
public ActionResult Callback(string code, string hmac, string shop, string state, string timestamp)
{
//this resolved the issue
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
Session["Workaround"] = 0;
return new ChallengeResult("Shopify", Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = "/Product/Products" }), null, shop.Replace(".myshopify.com", ""));
}
I am using the default ASP.net 'Register' method to create a new user from another controller:
public async Task<ActionResult> SyncNewUsers()
{
RegisterViewModel register = new RegisterViewModel();
register.UserName = item.entity_name;
register.Email = item.fields.preferred_email;
register.MobilePhone = item.fields.preferred_phone;
register.Password = "IT#test123";
register.ConfirmPassword = "IT#test123";
register.Role = "Admin";
await new AccountController().RegisterNewUser(register);
return View();
}
My 'Register' method:
public async Task<ActionResult> RegisterNewUser(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.UserName, Email = model.Email, PhoneNumber = model.MobilePhone };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await this.UserManager.AddToRoleAsync(user.Id, model.Role);
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
return RedirectToAction("newxpusers", "Users");
}
AddErrors(result);
}
return View(model);
}
However, it never gets further than var result = await UserManager.CreateAsync(user, model.Password); where I get the error: 'UserManager' threw an exception of type 'system.nullreferenceexception'
I would assume it's got something to do with the HttpContext in the UserManager, but I am unsure how to deal with this when I am passing the Model to this method on the fly, rather than through a standard form submission.
Ended up bypassing UserManager.CreateAsync(user, model.Password); by implementing the following:
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(new ApplicationDbContext()));
var result = await manager.CreateAsync(user, model.Password);
I know am probaby late but for posterities sake. I had the same error and I realised it was the password requirements after all. Make sure:
It contains a number
It contains a special character
It is 8 characters long
After doing this the record was inserted into the database so i suggest you make or check the password requirements before sending the form.
I am trying to create a user by calling register function within the application.
This function works fine when the function is called as a API.
When Called from Inside the application it throws an error
AccountController ac = new AccountController();
RegisterBindingModel rbm = new RegisterBindingModel();
rbm.Email = UserAccountBase.Email;
rbm.Password = "TestPassword";
rbm.ConfirmPassword = "TestPassword";
var userId = await ac.Register(rbm);
// POST api/Account/Register
[AllowAnonymous]
[Route("Register")]
[ApiExplorerSettings(IgnoreApi = true)]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
try
{
var result = await UserManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
}
catch(Exception e) {
var message = e.Message;
}
return Ok(user.Id);
}
UserManager.CreateAsync Throws an error
Value cannot be null. Parameter name: request
Did you build this using ASP Identity 2.0 and EF Code First? If so, check to see if your initial DB configuration put a column called 'Discriminator' at the end of AspNetUsers. If this is the case, recreate an initial migration and remove that column that gets generated. Once removed, you can perform an update-database. Does this make any sense? I just had this happen to me.
In the identity model, you will have a Discriminator column. In your model, add migration and update the database.
i create my own database and add user identity table to this by change the connection string.
now my connection string is this:
when i create a new user it worked well.
but when i change the Register(RegisterViewModel model) in RegisterControler to add a user to a role like this code:
public async Task Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
//add user to member role******************
if (!Roles.RoleExists("Member"))
Roles.CreateRole("Member");
Roles.AddUserToRole(model.Email, "Member");
//*******************************************
await SignInAsync(user, isPersistent: false);
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
// string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
// var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
// await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking here");
return RedirectToAction("Index", "Home");
}
else
{
AddErrors(result);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
user registerd but dont add to member Role! and it seem there is another connection string for Roles! beacause whene run this code ASPNETDB.MDF created in App_Data!
Please help me to solve this problem
In order to create roles in asp.net identity, you need to use AspNetRoleManager same as you are currently using AspNetUserManager.
The AspNetUserManager may looks like below.
public class AspNetRoleManager : RoleManager<IdentityRole, string>
{
public AspNetRoleManager(IRoleStore<IdentityRole, string> roleStore)
: base(roleStore)
{
}
public static AspNetRoleManager Create(IdentityFactoryOptions<AspNetRoleManager> options, IOwinContext context)
{
return new AspNetRoleManager(new RoleStore<IdentityRole, string, IdentityUserRole>(context.Get<YourDataContext>()));
}
}
Then you need to register AspNetRoleManager in the owin startup. Same like the AspNetUserManager.
app.CreatePerOwinContext<AspNetRoleManager>(AspNetRoleManager.Create);
After that you can use it inside the controller to create roles.
var roleManager = HttpContext.GetOwinContext().Get();
// Check for existing roles
var roleManager = HttpContext.GetOwinContext().Get<AspNetRoleManager>();
var roleExists = await roleManager.RoleExistsAsync("Member");
if (!roleExists)
{
var role = new IdentityRole();
role.Name = "Member";
var result = roleManager.CreateAsync(role);
}
Then add new role to the user.
var user = await UserManager.FindByEmailAsync(model.Email);
var roleRsult = UserManager.AddToRole(user.Id, roleName);
I am trying to get to grips with the new Membership system introduced in ASP.NET MVC 5 and I've come across a small issue which I am pretty sure you will be able to help me with.
I am going based off this tutorial and have introduced custom properties to ApplicationUser such as Name, Surname, DOB, etc.
However, instead of creating the user, I am trying to update the currently logged in one. I am looking at the controller method which is currently used to change password.
public async Task<ActionResult> Manage(ManageUserViewModel model)
{
string userId = User.Identity.GetUserId();
bool hasLocalLogin = await IdentityManager.Logins.HasLocalLoginAsync(userId);
ViewBag.HasLocalPassword = hasLocalLogin;
ViewBag.ReturnUrl = Url.Action("Manage");
if (hasLocalLogin)
{
if (ModelState.IsValid)
{
IdentityResult result = await IdentityManager.Passwords.ChangePasswordAsync(User.Identity.GetUserName(), model.OldPassword, model.NewPassword);
if (result.Success)
{
return RedirectToAction("Manage", new { Message = "Your password has been changed." });
}
else
{
AddErrors(result);
}
}
}
else
{
// User does not have a local password so remove any validation errors caused by a missing OldPassword field
ModelState state = ModelState["OldPassword"];
if (state != null)
{
state.Errors.Clear();
}
if (ModelState.IsValid)
{
// Create the local login info and link it to the user
IdentityResult result = await IdentityManager.Logins.AddLocalLoginAsync(userId, User.Identity.GetUserName(), model.NewPassword);
if (result.Success)
{
return RedirectToAction("Manage", new { Message = "Your password has been set." });
}
else
{
AddErrors(result);
}
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
How exactly would I go on about updating an ApplicationUser's Surname for example? Do I need to call the DbContext or?
I hope my question is clear.
Explore IdentityManager.Store.UserManagement and IdentityManager.Store.Users.
ApplicationUser cUser = (ApplicationUser) await IdentityManager.Store.Users.FindByNameAsync(HttpContext.User.Identity.Name, new System.Threading.CancellationToken());
cUser.Surname = "New Something";
IdentityResult result1 = await IdentityManager.Store.SaveChangesAsync();
Above code is an example only. Basically you need to explore the Store property of IdentityManage.
When we used the Users object of our database context we ran into other tracking errors. In our application, we would retrieve users as such
var user = UserManager.FindById(userId);
Edit the properties:
user.StorageName = "gooblygook";
//whatever other properties you would like to use
And then we would save it with the UserManager in the controller:
UserManager.Update(user);
This is currently a working solution for us.
Mark the Person object as virtual in your ApplicationUser definition. That worked for me.
public class ApplicationUser : IdentityUser
{
public virtual Person Person { get; set; }