简体   繁体   中英

ASP.NET Core resolve DbContext dependency to init migrations

It's great that ASP.NET DI works out-of-the-box and recursively resolves all constructor dependencies. Though sometimes you want to be able to access DI container directly. I am wondering if there is a way? Maybe something like this:

IService service = Container.Instance.Resolve<IService>();

I didn't find anything in the docs (though I know, I can replace built-in DI framework).


For the most part you don't need it, but there are some specific cases. In my situation I need to initialize my EF DbContext using IoC container on app start-up to initiate auto-migrations that supposed to work like that with EF Core:

using (var context = new MyContext())
{
    context.Database.Migrate();
}

My context is registered in container but it's in a separate class library. And I don't want to call it's DbContextOptions constructor directly.

After the question got updated and it's clear that it's going about EntityFramework Core migrations, there is an semi-official way form the ASP.NET Core team on how to correctly resolve the DbContext during application startup.

By default, the DbContext is registered as scoped service, so you get instantiated once per request. The catch during the application startup is, that there is no context yet and only app.ApplicationServices is available within Configure method and the ApplicationServices provider is essentially resolving singletons (scoped is a singleton per scope and application scope lives as long as the application does).

So the trick is to create a scope first, resolve the DbContext , do the operations and then dispose the context (and the DbContext with it).

Examples can be found in the MusicStore example application here and here .

As of right now, this is the only safe way to resolve it w/o causing any issues with ie disposed object exceptions.

Also please note, that the earliest point you can do this is in the Configure method, because only then the IoC container has been built. In ConfigureServices you only populate the IServiceCollection .

The relevant code snippets:

void Configure(IApplicationBuilder app)
{
    //Populates the MusicStore sample data
    SampleData.InitializeMusicStoreDatabaseAsync(app.ApplicationServices).Wait();
}

public static class SampleData
{
    ...

    public static async Task InitializeMusicStoreDatabaseAsync(IServiceProvider serviceProvider, bool createUsers = true)
    {
        using (var serviceScope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope())
        {
            var db = serviceScope.ServiceProvider.GetService<MusicStoreContext>();

            if (await db.Database.EnsureCreatedAsync())
            {
                await InsertTestData(serviceProvider);
                if (createUsers)
                {
                    await CreateAdminUser(serviceProvider);
                }
            }
        }
    }
}

Edit:

Additional resources regarding this issue:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM