简体   繁体   中英

ASP.NET Core 2 + Get instance of db context

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

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();
}

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();

see this question and he answerd himself in the 'Update' section

Add in program.cs at CreateWebHostBuilder method

 .UseDefaultServiceProvider(options => {
     options.ValidateScopes = false;//to use any scoped
     option.validateOnBuild = false;//to use dbContext 
})

The full code:

public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
    Host.CreateWebHostBuilder(args).ConfigureWebHostDefaults(webBuilder =>  
        {
            webBuilder.UseStartup<Startup>().UseDefaultServiceProvider(options =>
            {
                options.ValidateScopes = false;
                option.ValidateOnBuild = false;
            });
        })
}

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