Updating user by UserManager.Update() in ASP.NET Identity 2

Jack picture Jack · Sep 17, 2016 · Viewed 37.6k times · Source

I use ASP.NET Identity 2 in an MVC 5 project and I want to update Student data by using UserManager.Update() method. However, as I inherit from ApplicationUser class, I need to map Student to ApplicationUser before calling update method. On the other hand, when using the approach that I also used for creating new Student, there is an error due to concurrency as I create a new instance rather than update. As I am bored to solve the problem using AutoMapper, I need a stable fix to solve the problem without AutoMapper. Could you please clarify me how to solve this problem? I pass the StudentViewModel to the Update method in the Controller and then I need to map it to Student and then pass them to the UserManager.Update() method as ApplicationUser. On the other hand I am wondering if I should retrieve and send the password on Controller stage instead of passing to View for security concern? Could you also inform me about this issue (during User Update I do not update password and I have to keep the user's password in the database). Any help would be appreciated.

Entity Classes:

public class ApplicationUser : IdentityUser<int, ApplicationUserLogin,
                                     ApplicationUserRole, ApplicationUserClaim>, IUser<int>
{
    public string Name { get; set; }
    public string Surname { get; set; } 
    //code omitted for brevity
}

public class Student: ApplicationUser
{     
    public int? Number { get; set; }
}


Controller:

[HttpPost]
[ValidateAntiForgeryToken]
public JsonResult Update([Bind(Exclude = null)] StudentViewModel model)
{
    if (ModelState.IsValid)
    {
        ApplicationUser user = UserManager.FindById(model.Id);

        user = new Student
        {
            Name = model.Name,
            Surname = model.Surname,
            UserName = model.UserName,
            Email = model.Email,
            PhoneNumber = model.PhoneNumber,
            Number = model.Number, //custom property
            PasswordHash = checkUser.PasswordHash
        };

        UserManager.Update(user);
    }
}

Answer

Ivan Stoev picture Ivan Stoev · Sep 17, 2016

There is no need to pass the student as ApplicationUser to the UserManager.Update() method (because Student class inherits (hence is) ApplicationUser).

The problem with your code is that you are using new Student operator, thus creating a new student rather than updating the existing one.

Change the code like this:

// Get the existing student from the db
var user = (Student)UserManager.FindById(model.Id);

// Update it with the values from the view model
user.Name = model.Name;
user.Surname = model.Surname;
user.UserName = model.UserName;
user.Email = model.Email;
user.PhoneNumber = model.PhoneNumber;
user.Number = model.Number; //custom property
user.PasswordHash = checkUser.PasswordHash;

// Apply the changes if any to the db
UserManager.Update(user);