【问题标题】:ASP.NET Injecting DbContext into Identity UserManagerASP.NET 将 DbContext 注入 Identity UserManager
【发布时间】:2015-06-17 09:50:12
【问题描述】:

我有一个引用 AppUser 模型的 Question 模型。这是一个 1 到 * 的关系,因为 1 个 AppUser 有很多问题,而一个问题属于 1 个 AppUser。我的问题类如下所示:

public class Question
{
    public int Id { get; set; }
    public string Subject { get; set; }
    public string Text { get; set; }
    public DateTime Date { get; set; }
    public int NumOfViews { get; set; }
    public AppUser LastAnswerBy { get; set; }

    public AppUser AppUser { get; set; }
    public ICollection<Comment> Comments { get; set; }
}

所以我尝试向我的控制器中的数据库添加一个新问题,如下所示:

[HttpPost]
    public ActionResult PostQuestion(Question question)
    {
        if (ModelState.IsValid)
        {
            var id = User.Identity.GetUserId();
            var user = UserManager.Users.FirstOrDefault(x => x.Id == id);
            question.Date = DateTime.Now;
            question.AppUser = user;

            _context.Questions.Add(question);
            _context.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(question);
    }

    private AppUserManager UserManager
    {
        get { return HttpContext.GetOwinContext().GetUserManager<AppUserManager>(); }
    }

使用此代码,我得到如下异常: 一个实体对象不能被多个 IEntityChangeTracker 实例引用。所以在搜索了一下之后,问题似乎是我的控制器和 AppUserManager 类有两个不同的 DbContext 实例,解决方案是将它注入到这些类中。将它注入到我的控制器中没有问题,但我不知道如何将它注入到我的 UserManager 类中,如下所示:

public class AppUserManager : UserManager<AppUser>
{

    public AppUserManager(IUserStore<AppUser> store)
        : base(store)
    { }

    public static AppUserManager Create(IdentityFactoryOptions<AppUserManager> options,
    IOwinContext context)
    {
        AppIdentityDbContext db = context.Get<AppIdentityDbContext>();
        AppUserManager manager = new AppUserManager(new UserStore<AppUser>(db));

        return manager;
    }
}

它是从我的 IdentityConfig 类中调用的,如下所示:

public class IdentityConfig
{
    public void Configuration(IAppBuilder app)
    {
        app.CreatePerOwinContext<AppIdentityDbContext>(AppIdentityDbContext.Create);
        app.CreatePerOwinContext<AppUserManager>(AppUserManager.Create);
        app.CreatePerOwinContext<AppRoleManager>(AppRoleManager.Create);

        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
        });

        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
}

我的问题可能是我不太了解身份部分。非常感谢任何帮助

解决方案: 正如 Tobias 所说,我正在使用 2 个不同的上下文来更新数据库。像这样获取上下文是可行的:

private AppIdentityDbContext Context
    {
        get { return HttpContext.GetOwinContext().Get<AppIdentityDbContext>(); }
    }

【问题讨论】:

  • 控制器上的 _context 变量是如何实例化的?您是从 OWIN 上下文中获取 AppIdentityDbContext 吗?
  • 现在我只是在我的控制器顶部执行此操作:private AppIdentityDbContext _context = new AppIdentityDbContext();

标签: asp.net .net asp.net-mvc asp.net-identity


【解决方案1】:

你的问题很可能是你试图用两个不同的上下文做一件事。您正在使用一种上下文查找用户,并尝试使用另一种上下文更新数据库。要解决这个问题,您应该像这样在控制器中实例化您的上下文:

_context = HttpContext.GetOwinContext().Get<AppIdentityDbContext>();

这样,您将获得相同的上下文,用于实例化您的 AppUserManager

如果我弄错了,或者不清楚,请发表评论。 :)

【讨论】: