如何使用MVC5和entity framework使用自定义属性更新IdentityUser

我使用内置的身份框架进行用户管理,并希望为AspNetUsers表添加一些自定义。 到目前为止,我遇到的每个问题的解决方案都会导致另一个问题。

如果我更改用户模型(例如,通过在AspNetUsers表中添加邮政编码属性和匹配字段),然后调用UserManager.UpdateAsync(user),它会成功,但不会更新数据库中的邮政编码字段。

至少有一个其他SO问题试图解决这个问题。 但建议修复那里打破其他事情:

1)创建UserDbContext的另一个实例并尝试附加用户对象导致entity framework抱怨“实体对象不能被IEntityChangeTracker的多个实例引用”

2)关闭代理创建摆脱了#1中列出的问题, 但导致dbcontext不加载子对象 (如AspNetUserLogins,这是非常重要的)。

另一种解决方案是访问在Controller中创建的上下文。 使用MVC(版本5)模板考虑使用新的ASP .NET Web应用程序的默认AccountController的构造函数方法:

public AccountController() : this(new UserManager(new UserStore(new ApplicationDbContext()))) { } public AccountController(UserManager userManager) { UserManager = userManager; } 

创建应用程序数据库上下文,但无法通过UserManager访问它(因为UserManager的“存储”私有属性)。

这似乎不像是火箭科学,所以我的猜测是我在处理/理解dbcontext生命周期时做了一些基本上错误的事情。

那么:如何正确访问/使用dbcontext来保存和更新AspNetUsers,关联的自定义属性以及保留子对象(如AspNetUserLogins)?

编辑——-

还有一件事我试过……

我从默认更新了AccountController的构造函数:

  public AccountController(UserManager userManager) { UserManager = userManager; } 

对此:

  public AccountController(UserManager userManager) { userDbContext= new UserDbContext(); UserStore store = new UserStore(); UserManager manager = new UserManager(store); manager.UserValidator = new CustomUserValidator(UserManager); // UserManager = userManager; UserManager = manager; } 

试图挂起dbcontext。 后来,在公共异步任务方法的主体中,我尝试调用:

  var updated = await UserManager.UpdateAsync(user); if (updated.Succeeded) { userDbContext.Entry(user).State = System.Data.Entity.EntityState.Modified; await userDbContext.SaveChangesAsync(); } 

但是,尝试更新状态会引发exception:

“对象层类型’xyz.Models.ApplicationUser’已经生成了代理类型。当AppDomain中的两个或多个不同模型映射相同的对象层类型时,会发生这种情况。”

这似乎不正确……它与构造函数中分配的dbcontext相同。

编辑#2 —–

这是ApplicationUser模型:

 using Microsoft.AspNet.Identity.EntityFramework; using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNet.Identity; using System.Data.Entity; namespace xyz.App.Models { // You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more. public class ApplicationUser : IdentityUser { public string FirstName { get; set; } public string LastName { get; set; } public string ZipCode { get; set; } public string PasswordResetToken { get; set; } public System.DateTime? PasswordResetTokenExpiry { get; set; } public async Task GenerateUserIdentityAsync(UserManager 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 ApplicationUser() { } } public class UserDbContext : IdentityDbContext { public UserDbContext() : base("DefaultConnection") { } } } 

最终编辑—————————-

好吧,经过评论中的一些来回,我意识到我是以错误的方式提出问题。 我的问题是:如何使用代码优先而不是数据库优先迁移。 来自Hibernate学校,我习惯于通过XML或Java中的注释手动将对象映射到表。

因此,在浏览本文时 ,我错过了有关迁移的重要步骤。 学过的知识。

因此,您使用的是数据库优先而不是代码优先。 我的建议是使用代码优先。 我和你一样,首先开始使用数据库。 如果您不使用代码优先,则删除数据库中的迁移表。 否则会导致问题。

如果可能的话,我建议遵循这个代码优先的教程,这对我帮助很大。 您可以轻松地将自定义字段添加到您的身份中,并在身份validation过程中与框架完全集成。

http://blogs.msdn.com/b/webdev/archive/2013/10/16/customizing-profile-information-in-asp-net-identity-in-vs-2013-templates.aspx

我遇到了同样的问题。 解决这个问题的一种简单方法就是从模型中获取我想要更新的属性,并将它们保存回从UserManager中提取的对象;

  [HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit(ApplicationUser model) { if (ModelState.IsValid) { ApplicationUser u = UserManager.FindById(model.Id); u.UserName = model.Email; u.Email = model.Email; u.StaffName = model.StaffName; // Extra Property UserManager.Update(u); return RedirectToAction("Index"); } return View(model); }