我正在使用内置的身份框架进行用户管理,并且想向 AspNetUsers 表添加一些自定义项。到目前为止,我遇到的每个问题的解决方案都会导致另一个问题。
如果我对用户模型进行更改(例如,通过在 AspNetUsers 表中添加邮政编码属性和匹配字段),然后调用 UserManager.UpdateAsync(user),它会成功,但不会更新数据库中的邮政编码字段。
至少另外一个问题 https://stackoverflow.com/questions/20444022/updating-user-data-asp-net-identity已经尝试解决这个问题。但建议的修复方案还破坏了其他东西:
1) 创建 UserDbContext 的另一个实例并尝试附加用户对象会导致实体框架抱怨“实体对象不能被 IEntityChangeTracker 的多个实例引用”
2) 关闭代理创建可以解决 #1 中列出的问题,但会导致 dbcontext 不加载子对象 http://endanwang.blogspot.com/2012/05/side-effect-of-dbcontextconfigurationpr.html(比如AspNetUserLogins,这相当重要)。
另一个解决方案是访问控制器中创建的上下文。考虑使用 MVC(版本 5)模板的新 ASP .NET Web 应用程序的默认 AccountController 构造函数方法:
public AccountController()
: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
{
}
public AccountController(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
}
应用程序数据库上下文已创建,但无法通过 UserManager 访问它(因为 UserManager 的“Store”私有属性)。
这看起来不像火箭科学,所以我的猜测是我在处理/理解 dbcontext 生命周期方面做了一些基本上错误的事情。
那么:如何正确访问/使用 dbcontext 来保存和更新 AspNetUsers、关联的自定义属性并保留子对象(如 AspNetUserLogins)?
编辑 - - - -
我还尝试过一件事......
我更新了 AccountController 的默认构造函数:
public AccountController(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
}
to this:
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;
}
尝试挂起 dbcontext。后来,在公共异步任务方法的主体中,我尝试调用:
var updated = await UserManager.UpdateAsync(user);
if (updated.Succeeded)
{
userDbContext.Entry(user).State = System.Data.Entity.EntityState.Modified;
await userDbContext.SaveChangesAsync();
}
但是,尝试更新状态会引发异常:
“已经为对象层类型“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")
{
}
}
}
最终编辑----------------------------
好吧,经过一番评论后,我意识到我问问题的方式是错误的。我的问题实际上是:如何使用代码优先而不是数据库优先迁移。来自 Hibernate 学校的我习惯于通过 XML 或 Java 中的注释手动将对象映射到表。
所以,在略读中本文 http://www.asp.net/mvc/tutorials/mvc-5/create-an-aspnet-mvc-5-app-with-facebook-and-google-oauth2-and-openid-sign-on,我错过了有关迁移的重要步骤。学过的知识。