MVC5 ID UserManager.Update (user) not working
This is my first time using the first code in MVC5 for user management. I can change the password, but I cannot update the user registration. I've been combing the internet and literally looked at every question on this site related to UserManager.Update (user) that doesn't work.
using System.Data.Entity;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
namespace _100..Models
{
public class ApplicationUser : IdentityUser
{
public virtual PersonalInfo PersonalInfo { get; set; }
public virtual BillingInfo BillingInfo { get; set; }
public virtual DeliveryInfo DeliveryInfo { get; set; }
public Chapters Chapter { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
public class PersonalInfo
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class BillingInfo
{
public int ID { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
}
public class DeliveryInfo
{
public int ID { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false){}
public DbSet<PersonalInfo> PersonalInfo { get; set; }
public DbSet<BillingInfo> BillingInfo { get; set; }
public DbSet<DeliveryInfo> DeliveryInfo { get; set; }
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
}
And here is my action
[HttpPost]
public async Task<ActionResult> UpdateRegisteration(ApplicationUser user)
{
var result = await UserManager.UpdateAsync(user);
return RedirectToAction("Index", "Home");
}
I have confirmed that the custom object has updated data when it reaches the action and the update method returns success but does not actually update the database.
source to share
There are several levels of this fix. First when I ran UserManager.Update it was against the user object I got from my updateRegistration view. EF thought it was a new object and got an internal "UserName already exists" error and it failed but reported success. So I had to create a dbContext and update the state of the object to the changed one. But I found out that I also had to create a user object from the updated user id in order to set the username or the update failed. I found that I had to update PasswordHash or it will be null. Then I found that I also had to update the SecurityStamp, or the login process would fail. My action is below.
[HttpPost]
public async Task<ActionResult> UpdateRegisteration(ApplicationUser UpdatedUser)
{
var SavedUser = await UserManager.FindByIdAsync(UpdatedUser.Id);
try
{
UpdatedUser.SecurityStamp = SavedUser.SecurityStamp;
UpdatedUser.PasswordHash = SavedUser.PasswordHash;
UpdatedUser.UserName = SavedUser.UserName;
UpdatedUser.Id = SavedUser.Id;
UpdatedUser.PersonalInfo.ID = SavedUser.PersonalInfo.ID;
UpdatedUser.BillingInfo.ID = SavedUser.BillingInfo.ID;
UpdatedUser.DeliveryInfo.ID = SavedUser.DeliveryInfo.ID;
ApplicationDbContext db = new ApplicationDbContext();
db.Entry(UpdatedUser).State = EntityState.Modified;
db.Entry(UpdatedUser.PersonalInfo).State = EntityState.Modified;
db.Entry(UpdatedUser.BillingInfo).State = EntityState.Modified;
db.Entry(UpdatedUser.DeliveryInfo).State = EntityState.Modified;
await db.SaveChangesAsync();
// var result = await UserManager.UpdateAsync(SavedUser);
return RedirectToAction("Index", "Home");
}
catch (System.Data.Entity.Validation.DbEntityValidationException dbEx)
{
Exception raise = dbEx;
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
string message = string.Format("{0}:{1}",
validationErrors.Entry.Entity.ToString(),
validationError.ErrorMessage);
// raise a new exception nesting
// the current instance as InnerException
raise = new InvalidOperationException(message, raise);
}
}
throw raise;
}
}
source to share