web-dev-qa-db-ja.com

ASP.NET Core 2 + DBコンテキストのインスタンスを取得

DbContextのインスタンスを取得しようとしています(したがって、起動時に追加の作業を行うことができます)。Configureメソッドでインスタンスを取得しようとすると、次のエラーが表示されます。

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

コントローラなどを介してDbContextのインスタンスに正常にアクセスできます。

18
TheWebGuy

Paul Hilesのコメントは正しいが、その方法は.NET Core 1.0でより適切に機能する。

ASP.NET Core 2.0では、Startup.csでデータベースのセットアップを実行することは一般に悪い考えです。これは、CLIまたはVisual Studioから移行を実行すると、Startup.csのすべてが実行され、構成を実行しようとして失敗するためです。もちろん、Entity-Frameworkを使用しない場合、これは問題ではありませんが、2.0で推奨される方法ではありません。 Program.csで行うことをお勧めします。

たとえば、必要なセットアップを実行する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;
}

そして、Program.csで、実行する前にそのメソッドを呼び出すことができます。

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

Core 2.1以降のアップデート

@ Travis Boatman の優れた答えに追加するために、推奨されるMainメソッドの構文は Core 2.1以降わずかに変更されました とデフォルトのMainメソッドにCreateWebHostBuilderの代わりにBuildWebHostが追加されました。

拡張メソッドを呼び出すための修正されたコードを以下に示します。

注意:ここでは順序が重要です。BuildメソッドはWebHostを返します。これは拡張メソッドが拡張しているものです。したがって、Build()の後にmigrateメソッドを呼び出す必要がありますおよびRun())の前:

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

複数の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;
}

その後、呼び出しを連鎖させて、異なるコンテキストを移行できます。

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