在App_Start中初始化和播种Identity的DbContext

时间:2014-09-07 18:27:45

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

我使用的是最新的MVC,Identity,EntityFramework以及官方Identity sample solution

有很多方法可以在App_Start()中运行数据库初始化程序(例如DropCreateDatabaseIfModelChangesDropCreateDatabaseAlways)。

我试过了:

AppDbContext.Instance.Database.Initialize(true); // Instance is static builder 

问题在于,使用Identity / OWIN,播种函数会将管理器对象拉出OWIN上下文(通过HttpContext.Current.GetOwinContext()),这显然在生命周期的早期并不存在。

var userManager = HttpContext.Current.GetOwinContext().GetUserManager<UserManager>();
var roleManager = HttpContext.Current.GetOwinContext().Get<RoleManager>();

所以我得到了:

InvalidOperationException: No owin.Environment item was found in the context.

正确设置OWIN上下文,并按预期运行。只有当我尝试在App_Start中访问它时我才会遇到此问题。

App_Start中初始化db并不是绝对必要的,但我更喜欢显式代码,并且需要各种初始化例程,包括db的创建/接种。我该怎么做?

1 个答案:

答案 0 :(得分:10)

@BrendanGreen的评论给了我一个想法,这对我有用。下面的所有内容都只是我对Identity示例项目的编辑。

首先修改DbContextInitializer

public class DbContextInitializer : DropCreateDatabaseIfModelChanges<AppDbContext> {

  protected override void Seed(AppDbContext context) {

    // remove this, because the OWIN context does not yet exist:
    //var userManager = HttpContext.Current.GetOwinContext().GetUserManager<AppUserManager>();
    //var roleManager = HttpContext.Current.GetOwinContext().Get<AppRoleManager>();

    // and replace it with:
    var userManager = new AppUserManager<AppUser>(new UserStore<AppUser>(context));
    var roleManager = new AppRoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));

    // ... etc. ...

    base.Seed(context);
  }

}

然后修改AppDbContext

public class AppDbContext : IdentityDbContext<AppUser> {

  // no change: this static factory method is called in OWIN init
  public static AppDbContext Create() { return new AppDbContext(); }

  // no change: this static ctor called the first time this type is referenced
  static AppDbContext() { Database.SetInitializer<AppDbContext>(new DbContextInitializer()); }

  // changed: made ctor private
  private AppDbContext() : base("name=DefaultConnection", false) { }

  // add this: forces the initializer to run, even if it's already been run
  public static void init() { Create().Database.Initialize(true); }

}

最后编辑Global.asax.cs

protected void Application_Start() {
  // ... etc.
  DbContext.init();                            // force initializer to run
  // ... etc.
  }

结果是db不再是延迟创建/延迟加载的,而是在Application_Start中初始化。这有必要吗?不。但是现在我的所有初始化代码都出现在一个地方,并且在调试时更容易跟踪事情。