5

I'm using the latest MVC, Identity, EntityFramework, as well as the official Identity sample solution.

There are lots of ways to run a database initializer in the App_Start(), (e.g. (DropCreateDatabaseIfModelChanges, DropCreateDatabaseAlways).

I tried:

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

Problem is that with Identity/OWIN, the seeding function pulls manager objects out of the OWIN context (via HttpContext.Current.GetOwinContext()), which apparently, doesn't exist that early in the lifecycle.

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 setup properly, and runs as expected. It's only if I try access it in App_Start that I get this problem.

Initializing the db in App_Start is not strictly necessary, but I prefer explicit code, and want various init routines in there, including creation/seeding of the db. How do I do that?

2
  • 1
    Can't you just create an instance of UserManager and/or RoleManager instead? Commented Sep 7, 2014 at 21:44
  • @BrendanGreen didn't know I could od that without going through OWIN. Added an answer which works for me. Commented Sep 8, 2014 at 7:26

1 Answer 1

10

@BrendanGreen's comment gave me an idea, which works on my side. All the stuff below is simply my edits to the Identity sample project.

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

And finally edit the Global.asax.cs:

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

The result is that the db is no longer lazy-created / lazy-loaded, but rather initialized in the Application_Start. Is this necessary? No. But now all my init code occurs in one place and it's easier to keep track of things when debugging.

Sign up to request clarification or add additional context in comments.

3 Comments

Kudos for sorting your own problem
So how does OWIN come in to all this in the final solution?
What nuget package are you using to get DropCreateDatabaseIfModelChanges? When I try and use EntityFramework and System.Data.Entity I get an error of converting my context to System.Data.Entity.DbContext.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.