1

I am having a hard time figuring out how to update/modify a user in my AspNetUsers table using the Entity Framework and Identity. I am getting an error that says:

"The entity type ManagerUserViewModel is not part of the model for the current context."

This make sense, because I do not mention the ManagerUserViewModel in the ApplicationDbContext which I am using. But should I create a new Context similar to ApplicationDBContext and use that one? Or do I somehow add my ManagerUserViewModel to the ApplicationDBContext?

Here is my controller method that is doing the updating when 'Save' is clicked:

public ActionResult EditUser([Bind(Include = "UserID, Email, UserName, Roles, RoleID, RoleName")] ManagerUserViewModel model)
    {
        if (ModelState.IsValid)
        {
            using (var context = new ApplicationDbContext())
            {
                var store = new UserStore<ApplicationUser>(context);
                var manager = new UserManager<ApplicationUser>(store);
                ApplicationUser user = new ApplicationUser();
                user.Email = model.Email;
                user.UserName = model.UserName;

                if (model.UserID == "")
                {
                    // Since it didn't have a UserID, we assume this is a new User

                    Task.WaitAny(manager.CreateAsync(user, "Password12"));
                }
                else
                {
                    // Since EF doesn't know about this product (it was instantiated by
                    // the ModelBinder and not EF itself, we need to tell EF that the
                    // object exists and that it is a modified copy of an existing row

                    context.Entry(model).State = EntityState.Modified;

                    Task.WaitAny(manager.UpdateAsync(user));
                }
                if (model.RoleName != null && model.RoleName != "")
                {
                    Task.WaitAny(manager.AddToRoleAsync(model.UserID, model.RoleName));
                }
                Task.WaitAny(context.SaveChangesAsync());
                return RedirectToAction("ControlPanel");
            }
        }
        return View(model);
    }

And here is my ManagerUserViewModel:

public class ManagerUserViewModel
{
    public String UserID { get; set; }
    public String Email { get; set; }
    public String UserName { get; set; }

    [Display(Name = "Role(s)")]
    public IEnumerable<String> Roles { get; set; }

    public String RoleID { get; set; }

    public String RoleName { get; set; }

    public IEnumerable<SelectListItem> RoleList { get; set; }

    public static IEnumerable<SelectListItem> getRoles(string id = "")
    {
        using (var db = new ApplicationDbContext())
        {

            List<SelectListItem> list = new List<SelectListItem>();
            foreach (var role in db.Roles)
            {
                SelectListItem sli = new SelectListItem { Value = role.Name, Text = role.Name};
                list.Add(sli);
            }

            return list;
        }
    }

    public static String getRoleID(string role)
    {
        using (var db = new IdentityDbContext())
        {
            string roleID = db.Roles.Where(r => r.Name == role).First().Id;
            return roleID;
        }
    }
}

And here is my ApplicationDBContext:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }

    public DbSet<RegisterViewModel> RegisterUsers { get; set; }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }

}

Let me know if any other code is needed.

Edit: Based on Steve's comment, I tried creating a new Context.

public class ManageUserDbContext : IdentityDbContext<ApplicationUser>
{
    public ManageUserDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }

    public DbSet<ManagerUserViewModel> Users { get; set; }

    public static ManageUserDbContext Create()
    {
        return new ManageUserDbContext();
    }

}

And then in the Controller method, I switched my using context to new ManageUserDbContext(). Now it does not error out, but it still does not update the user.

2
  • Another option is to just make your application context inherit the identity context. typecastexception.com/post/2014/04/20/… Commented May 29, 2015 at 19:10
  • I tried creating a new context inheriting IdentityDbContext. I edited my post above. Commented May 29, 2015 at 19:24

2 Answers 2

1

You almost got it right. There is no need to use DbContext to update User when you have UserManager there.

Your code should be something like this :

public ActionResult EditUser([Bind(Include = "UserID, Email, UserName, Roles, RoleID, RoleName")] ManagerUserViewModel model)
{
    if (ModelState.IsValid)
    {
        using (var context = new ApplicationDbContext())
        {
            var store = new UserStore<ApplicationUser>(context);
            var manager = new UserManager<ApplicationUser>(store);
            ApplicationUser user = new ApplicationUser();
            user.Email = model.Email;
            user.UserName = model.UserName;

            if (model.UserID == "")
            {
                // Since it didn't have a UserID, we assume this is a new User

                Task.WaitAny(manager.CreateAsync(user, "Password12"));
            }
            else
            {
                // here we fetch existing user, update properties and call manager update 


                user = manager.FindById(model.UserID)
                user.Email = model.Email;
                user.UserName = model.UserName; 

                Task.WaitAny(manager.UpdateAsync(user));
            }
            if (model.RoleName != null && model.RoleName != "")
            {
                Task.WaitAny(manager.AddToRoleAsync(model.UserID, model.RoleName));
            }
            Task.WaitAny(context.SaveChangesAsync());
            return RedirectToAction("ControlPanel");
        }
    }
    return View(model);
}
Sign up to request clarification or add additional context in comments.

2 Comments

On the line user = await manager.FindByIdAsync(model.UserID) I am getting the error The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task<System.Web.Mvc.ActionResult>
I have updated answer. User non-async version of that method: FindById
1

Get rid of ManagerUserViewModel. By inheriting you have access to Users automatically and code like this should work:

    [HttpPost]
    [Authorize(Roles = "Admin")]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Edit(EditUserViewModel editUserViewModel)
    {
        if (!ModelState.IsValid) return View(editUserViewModel);

        ApplicationUser user = _db.Users.First(u => u.UserName == editUserViewModel.UserName);
        user = Mapper.Map(editUserViewModel, user);
        await _db.SaveChangesAsync();

        return RedirectToAction("Index").WithSuccess("User updated.");
    }

Note that I don't need the DbSet for Users or any mapping, etc. I can add custom fields to my ApplicationUser model:

   public class ApplicationUser : IdentityUser
   {
    [Required]
    [MaxLength(50)]
    public string FirstName { get; set; }

    [Required]
    [MaxLength(50)]
    public string LastName { get; set; }

    [MaxLength(5)]
    public string PhoneExtension { get; set; }

    [Required]
    [MaxLength(4)]
    public string DefaultDistrictNumber { get; set; }

}

To create a user you need to call UserManager and RoleManager.

4 Comments

I found an ApplicationUser class in my IdentityModel. Is that the class you are referring to?
What is in your EditUserViewModel?
Where you put EditUserViewModel can I pass ApplicationUser instead?
Generally you want to compose view models that you pass to your views. The common pattern is get the entity model from EF, map them to a view model (automapper is handy for this), add other needed data to the view model including validation and other attributes, then in Post method move the viewmodel back to the entity model for updating.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.