简体   繁体   English

ASP.NET 核心 2 + 获取数据库上下文实例

[英]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:我正在尝试获取 DbContext 的实例(因此我可以在启动时使用它做一些额外的工作),当我尝试在 Configure 方法中获取实例时出现以下错误:

System.InvalidOperationException: 'Cannot resolve scoped service 'MyApp.Data.MyDbContext' from root provider.' System.InvalidOperationException:“无法从根提供程序解析范围内的服务‘MyApp.Data.MyDbContext’。”

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我可以通过 controller 等访问 DbContext 的实例

Paul Hiles comment is correct but that method works better in .NET Core 1.0. Paul Hiles 的评论是正确的,但该方法在 .NET Core 1.0 中效果更好。

In ASP.NET Core 2.0 it's generally a bad idea to run any database setup in Startup.cs .在 ASP.NET Core 2.0 中,在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.这是因为如果您从 CLI 或 Visual Studio 运行任何迁移,它将运行所有Startup.cs并尝试运行将失败的配置。 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.当然,如果你不使用实体框架,那么这不是问题,但它仍然不是 2.0 中推荐的方法。 It's now recommended to do it in Program.cs .现在建议在Program.cs

For example you can create a extension method of IWebHost that will run any setup you need.例如,您可以创建IWebHost的扩展方法,它将运行您需要的任何设置。

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.然后在Program.cs您可以在运行之前调用该方法。

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

Update for Core 2.1 onwards Core 2.1 以上的更新

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 .只是为了添加@Travis Boatman的优秀答案,首选的Main方法语法从 Core 2.1 开始略有变化,默认Main方法现在使用CreateWebHostBuilder而不是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() ):注意:这里的顺序很重要, Build方法返回一个WebHost ,这是扩展方法所扩展的,因此您需要在Build()Run()之前调用 migrate 方法):

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

Migrating more than one DbContext迁移多个 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 :我们的项目中有多个DbContext ,因此我将扩展方法更改为可以采用任何类型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 methodprogram.cs中添加CreateWebHostBuilder方法

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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