29

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);
    }
}
3
  • 1
    Are you using custom table student and using microsoft identity for inserting data in student table?? Commented Sep 23, 2016 at 7:46
  • 1
    No, I just use the same table (AspNetUsers) and my Student entity inherits from ApplicationUser. Is there a smarter solution than the answer?
    – Jack
    Commented Sep 23, 2016 at 8:23
  • 1
    Actually i am struggling with this scenario:stackoverflow.com/questions/39304464/… Commented Sep 23, 2016 at 9:40

3 Answers 3

68

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);
6
  • 1
    Dear Ivan, many thanks for your help. Actually I had tried the same way as you mentioned, but in this case the problem is that: there is no Number property in user instance. For this reason I had to convert this instance to Student (in order to access Number property). On the other hand yes, for updating this is a mistake to create a new instance rather than using the current one. But no way to solve the problem :( Any other solution? I have searched a solution of this problem for days but no proper solution :(((
    – Jack
    Commented Sep 17, 2016 at 10:19
  • 1
    Then may be the problem is with the UserManager. I'm afraid this is outside from my area of knowledge, maybe someone else will help you, good luck (I've tried my best, but since I can't test, I believe you that it's not working, so I'm going to delete the answer in a minutes).
    – Ivan Stoev
    Commented Sep 17, 2016 at 10:47
  • 3
    Do not delete the answer. I solved the problem with the help of your valuable helps. Just change the first line as var user = UserManager.FindById(model.Id) as Student; in your answer :) Thanks a lot...
    – Jack
    Commented Sep 17, 2016 at 11:03
  • 2
    Could you please update your answer so that others can also benefit from it?
    – Jack
    Commented Sep 17, 2016 at 11:25
  • Does this check that a DIFFERENT user doesn't already exist with the same Username and or Email (assuming they changed those things)
    – niico
    Commented Mar 10, 2023 at 12:19
9

my answer on .netcore 1

this work for my, I hope can help them

var user = await _userManager.FindByIdAsync(applicationUser.Id);
                    user.ChargeID = applicationUser.ChargeID;
                    user.CenterID = applicationUser.CenterID;
                    user.Name  = applicationUser.Name;
var result = await _userManager.UpdateAsync(user);
1

This took me a little while to understand, but you simply need to use the UserManager. My task was to simply update the LoginViewModel with a new Date. I tried different methods, but the only thing that seemed to work was FindByEmailAsync, which is specific to my MODEL because I'm not using Id to sign in.

Case SignInStatus.Success
            Dim user As ApplicationUser = Await UserManager.FindByEmailAsync(model.Email)
            user.LastActivityDate = model.LastActivityDate

            UserManager.Update(user)

            Return RedirectToLocal(returnUrl)

Not the answer you're looking for? Browse other questions tagged or ask your own question.