Help us understand the problem. What is going on with this article?

dotnet ef migrations でエラーになった話

結論

  • ASP.NET Core 2.2 アプリで dotnet ef コマンドを実行する場合は、 Program.csCreateWebHostBuilder メソッドが必要。
    • ここから EF Core CLI が ASP.NET Core アプリの情報 (DB 接続先とか) にアクセスする。
    • ただし、.NET Core 3.0 だと名前が変わるから注意! (CreateHostBuilder)
  • dotnet ef コマンドのエラー調査には -v オプション (--verbose) を使おう

事象

ASP.NET Core & EFCore のチュートリアルを触っていて、DB マイグレーションができなかった。
C# コードでモデルを定義し、 EF Core のマイグレーションコマンド (dotnet ef migrations add InitialCreate) を実行したところ、エラー発生。

$ dotnet ef migrations add InitialCreate
Unable to create an object of type 'BloggingContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728

-v オプションで詳細表示したところ、原因が判明した。

$ dotnet ef migrations add InitialCreate -v
Using project 'C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\AspNetSample.csproj'.
Using startup project 'C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\AspNetSample.csproj'.
Writing 'C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\obj\AspNetSample.csproj.EntityFrameworkCore.targets'...
dotnet msbuild /target:GetEFProjectMetadata /property:EFProjectMetadataFile=C:\Users\wukan\AppData\Local\Temp\tmpF769.tmp /verbosity:quiet /nologo C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\AspNetSample.csproj
Writing 'C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\obj\AspNetSample.csproj.EntityFrameworkCore.targets'...
dotnet msbuild /target:GetEFProjectMetadata /property:EFProjectMetadataFile=C:\Users\wukan\AppData\Local\Temp\tmp24.tmp /verbosity:quiet /nologo C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\AspNetSample.csproj
dotnet build C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\AspNetSample.csproj /verbosity:quiet /nologo

ビルドに成功しました。
    0 個の警告
    0 エラー

経過時間 00:00:06.14
dotnet exec --depsfile C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\bin\Debug\netcoreapp3.0\AspNetSample.deps.json --additionalprobingpath C:\Users\wukan\.nuget\packages --additionalprobingpath "C:\Program Files\dotnet\sdk\NuGetFallbackFolder" --runtimeconfig C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\bin\Debug\netcoreapp3.0\AspNetSample.runtimeconfig.json "C:\Program Files\dotnet\sdk\3.0.100-preview3-010431\DotnetTools\dotnet-ef\3.0.0-preview3.19153.1\tools\netcoreapp3.0\any\tools\netcoreapp2.0\any\ef.dll" migrations add InitialCreate --assembly C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\bin\Debug\netcoreapp3.0\AspNetSample.dll --startup-assembly C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\bin\Debug\netcoreapp3.0\AspNetSample.dll --project-dir C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\ --language C# --working-dir C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample --verbose --root-namespace AspNetSample
Using assembly 'AspNetSample'.
Using startup assembly 'AspNetSample'.
Using application base 'C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\bin\Debug\netcoreapp3.0'.
Using working directory 'C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample'.
Using root namespace 'AspNetSample'.
Using project directory 'C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\'.
Finding DbContext classes...
Finding IDesignTimeDbContextFactory implementations...
Finding application service provider...
Finding IWebHost accessor...
No CreateWebHostBuilder(string[]) method was found on type 'AspNetSample.Program'.
No application service provider was found.
Finding DbContext classes in the project...
Found DbContext 'BloggingContext'.
Using context 'BloggingContext'.
System.InvalidOperationException: No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for DbContext.
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.Initialize(IServiceProvider scopedProvider, IDbContextOptions contextOptions, DbContext context)
   at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
   at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance()
   at Microsoft.EntityFrameworkCore.Internal.InternalAccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func`1 factory)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_1.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for DbContext.

No CreateWebHostBuilder(string[]) method was found on type 'AspNetSample.Program'. というメッセージに注目。どうやら、EF Core CLI は ASP.NET Core アプリケーションの Program クラスに定義されている (であろう) CreateWebHostBuilder メソッドを必要とする模様。これはプロジェクト作成時 (dotnet new) に自動生成されているハズ…なのだが、自分の環境では違う名前になっていたため、エラーが発生した。

解決方法

Program.csCreateWebHostBuilder メソッドをちゃんと定義し、

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

    public static IHostBuilder CreateWebHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

再度マイグレーションコマンド実行。

dotnet ef migrations add InitialCreate -v
Using project 'C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\AspNetSample.csproj'.
Using startup project 'C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\AspNetSample.csproj'.
Writing 'C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\obj\AspNetSample.csproj.EntityFrameworkCore.targets'...
dotnet msbuild /target:GetEFProjectMetadata /property:EFProjectMetadataFile=C:\Users\wukan\AppData\Local\Temp\tmpA315.tmp /verbosity:quiet /nologo C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\AspNetSample.csproj
Writing 'C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\obj\AspNetSample.csproj.EntityFrameworkCore.targets'...
dotnet msbuild /target:GetEFProjectMetadata /property:EFProjectMetadataFile=C:\Users\wukan\AppData\Local\Temp\tmpA9DD.tmp /verbosity:quiet /nologo C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\AspNetSample.csproj
dotnet build C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\AspNetSample.csproj /verbosity:quiet /nologo

ビルドに成功しました。
    0 個の警告
    0 エラー

経過時間 00:00:03.59
dotnet exec --depsfile C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\bin\Debug\netcoreapp3.0\AspNetSample.deps.json --additionalprobingpath C:\Users\wukan\.nuget\packages --additionalprobingpath "C:\Program Files\dotnet\sdk\NuGetFallbackFolder" --runtimeconfig C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\bin\Debug\netcoreapp3.0\AspNetSample.runtimeconfig.json "C:\Program Files\dotnet\sdk\3.0.100-preview3-010431\DotnetTools\dotnet-ef\3.0.0-preview3.19153.1\tools\netcoreapp3.0\any\tools\netcoreapp2.0\any\ef.dll" migrations add InitialCreate --assembly C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\bin\Debug\netcoreapp3.0\AspNetSample.dll --startup-assembly C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\bin\Debug\netcoreapp3.0\AspNetSample.dll --project-dir C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\ --language C# --working-dir C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample --verbose --root-namespace AspNetSample
Using assembly 'AspNetSample'.
Using startup assembly 'AspNetSample'.
Using application base 'C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\bin\Debug\netcoreapp3.0'.
Using working directory 'C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample'.
Using root namespace 'AspNetSample'.
Using project directory 'C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\'.
Finding DbContext classes...
Finding IDesignTimeDbContextFactory implementations...
Finding application service provider...
Finding IWebHost accessor...
Using environment 'Development'.
Using application service provider from IWebHost accessor on 'Program'.
Found DbContext 'BloggingContext'.
Finding DbContext classes in the project...
Using context 'BloggingContext'.
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
      Entity Framework Core 2.2.3-servicing-35854 initialized 'BloggingContext' using provider 'Pomelo.EntityFrameworkCore.MySql' with options: ServerVersion 8.0.15 MySql
Finding design-time services for provider 'Pomelo.EntityFrameworkCore.MySql'...
Using design-time services from provider 'Pomelo.EntityFrameworkCore.MySql'.
Finding design-time services referenced by assembly 'AspNetSample'.
No referenced design-time services were found.
Finding IDesignTimeServices implementations in assembly 'AspNetSample'...
No design-time services were found.
Writing migration to 'C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\Migrations\20190323131849_InitialCreate.cs'.
Writing model snapshot to 'C:\Users\wukan\Documents\work\dotnetcore\SqlPuzzle\src\AspNetSample\Migrations\BloggingContextModelSnapshot.cs'.
Done. To undo this action, use 'ef migrations remove'

成功!٩(๑´0`๑)۶
Using application service provider from IWebHost accessor on 'Program'. とあるように、今度はちゃんと ASP.NET Core アプリケーションの情報を読み込んでくれた模様。

蛇足

この CreateWebHostBuilder というメソッド、 .NET Core 2.2 -> 3.0 で名前が変更になる (CreateHostBuilder)。よって .NET Core バージョンアップ時には注意が必要。

実は過去 (.NET Core 2.0 -> 2.1) にも名前が変わっている模様。
https://github.com/aspnet/Docs/issues/7087
名前が安定しない… (´・ω・`)

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away