如何使用MVC5和实体框架使用自定义属性更新IdentityUser

Goj*_*tah 20 c# asp.net-mvc entity-framework

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

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

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

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

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

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

 public AccountController()
            : this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
        {
        }

        public AccountController(UserManager<ApplicationUser> userManager)
        {
            UserManager = userManager;
        }
Run Code Online (Sandbox Code Playgroud)

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

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

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

编辑-------

还有一件事我试过......

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

    public AccountController(UserManager<ApplicationUser> userManager)
    {
       UserManager = userManager;
    }
Run Code Online (Sandbox Code Playgroud)

对此:

    public AccountController(UserManager<ApplicationUser> userManager)
    {
        userDbContext= new UserDbContext();
        UserStore<ApplicationUser> store = new UserStore<ApplicationUser>();
        UserManager<ApplicationUser> manager = new UserManager<ApplicationUser>(store);

        manager.UserValidator = new CustomUserValidator<ApplicationUser>(UserManager);

       // UserManager = userManager;
        UserManager = manager;

    }
Run Code Online (Sandbox Code Playgroud)

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

  var updated = await UserManager.UpdateAsync(user);

  if (updated.Succeeded)
  {
    userDbContext.Entry(user).State = System.Data.Entity.EntityState.Modified;
    await userDbContext.SaveChangesAsync();
  }
Run Code Online (Sandbox Code Playgroud)

但是,更新状态的尝试会引发异常:

"对象层类型'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<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 ApplicationUser() { }

    }




    public class UserDbContext : IdentityDbContext<ApplicationUser>
    {
        public UserDbContext()
            : base("DefaultConnection")
        {

        }

    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

因此,在略读这篇文章时,我错过了有关迁移的重要步骤.学过的知识.

Jos*_*osh 33

我遇到了同样的问题.解决这个问题的一个简单方法就是从模型中获取我想要更新的属性,并将它们保存回从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);
    }
Run Code Online (Sandbox Code Playgroud)


use*_*388 10

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

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

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