我使用的是最新的MVC,Identity,EntityFramework以及官方Identity sample solution。
有很多方法可以在App_Start()
中运行数据库初始化程序(例如DropCreateDatabaseIfModelChanges
,DropCreateDatabaseAlways
)。
我试过了:
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的创建/接种。我该怎么做?
答案 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
中初始化。这有必要吗?不。但是现在我的所有初始化代码都出现在一个地方,并且在调试时更容易跟踪事情。