Initialization and seeding of Identity DbContext in App_Start

I use the latest MVC, Identity, EntityFramework, as well as the official sample solution .

There are many ways to start the database initializer in App_Start() (for example, ( DropCreateDatabaseIfModelChanges , DropCreateDatabaseAlways ).

I tried:

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

The problem is that using Identity / OWIN, the seeding function pulls manager objects from the OWIN context (via HttpContext.Current.GetOwinContext() ), which apparently does not exist, which is an early stage of the life cycle.

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

So, I get:

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

The OWIN context is configured correctly and works as expected. This is only if I try to access it in App_Start to get this problem.

Initializing db in App_Start not strictly necessary, but I prefer explicit code and want various init routines, including creating / fetching db, to be there. How to do it?

+5
source share
1 answer

Comment by @BrendanGreen gave me an idea that works on my side. All of the following are just my changes to the Identity sample design.

First edit the 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); } } 

Then edit the 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 already been run public static void init() { Create().Database.Initialize(true); } } 

And finally edit Global.asax.cs :

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

As a result, db ceases to be lazy / lazy, but initialized to Application_Start . It's necessary? Not. But now all my initialization code is found in one place, and it’s easier to track everything during debugging.

+9
source

Source: https://habr.com/ru/post/1202020/


All Articles