ASP.NET Core 2 + Get instance of db context

asp.net-core entity-framework-core

Question

I am trying to get an instance of the DbContext (so I can do some additional work upon startup with it), I get the following error when trying to get an instance in the Configure method:

System.InvalidOperationException: 'Cannot resolve scoped service 'MyApp.Data.MyDbContext' from root provider.'

public void ConfigureServices(IServiceCollection services)
{
 services.AddDbContext<MyDbContext>(
                options => options.UseSqlServer(Configuration.GetConnectionString("MyDbContext")));
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{

    var dbContext = app.ApplicationServices.GetService(typeof(MyDbContext)) as MyDbContext;
}

I can access an instance of the DbContext fine via the controller, etc

1
21
8/25/2017 3:40:59 PM

Accepted Answer

Paul Hiles comment is correct but that method works better in .NET Core 1.0.

In ASP.NET Core 2.0 it's generally a bad idea to run any database setup in Startup.cs. This is because if you run any migrations from the CLI or Visual Studio it will run all of Startup.cs and try to run your configuration which will fail. Of course if you don't use Entity-Framework then this isn't a problem however its still not the recommended way of doing it in 2.0. It's now recommended to do it in Program.cs.

For example you can create a extension method of IWebHost that will run any setup you need.

public static IWebHost MigrateDatabase(this IWebHost webHost)
{
    var serviceScopeFactory = (IServiceScopeFactory)webHost.Services.GetService(typeof(IServiceScopeFactory));

    using (var scope = serviceScopeFactory.CreateScope())
    {
        var services = scope.ServiceProvider;
        var dbContext = services.GetRequiredService<YourDbContext>();

        dbContext.Database.Migrate();
    }

    return webHost;
}

And then in Program.cs you can then call that method before running.

public static void Main(string[] args)
{
    BuildWebHost(args)
        .MigrateDatabase()
        .Run();
}
33
2/22/2018 9:29:35 AM

Popular Answer

Update for Core 2.1 onwards

Just to add to @Travis Boatman's excellent answer, the preferred Main method syntax has changed slightly from Core 2.1 onwards and the default Main method now has CreateWebHostBuilder instead of BuildWebHost.

The revised code to call the extension method is shown below.

NB: the order is important here, the Build method returns a WebHost, which is what the extension method is extending, so you need to call the migrate method after Build() and before Run()):

public static void Main(string[] args)
{
    CreateWebHostBuilder(args)
        .Build()
        .MigrateDatabase()
        .Run();
}

Migrating more than one DbContext

We have more than one DbContext in our project, so I changed the extension method to a generic method that can take any type of DbContext:

public static IWebHost MigrateDatabase<T>(this IWebHost webHost) where T:DbContext
{
    var serviceScopeFactory = (IServiceScopeFactory)webHost
        .Services.GetService(typeof(IServiceScopeFactory));

    using (var scope = serviceScopeFactory.CreateScope())
    {
        var services = scope.ServiceProvider;

        var dbContext = services.GetRequiredService<T>();
        dbContext.Database.Migrate();
    }

    return webHost;
}

You can then chain the calls to migrate the different contexts:

CreateWebHostBuilder(args)
    .Build()
    .MigrateDatabase<ApiAuthDbContext>()
    .MigrateDatabase<MainDbContext>()
    .MigrateDatabase<SomeOtherDbContext>()
    .Run();


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow