Unable to create a 'DbContext' of type 'ClinicDb' from
dotnet ef migrations add means the EF tools found your context but had no way to
build it: its constructor wants DbContextOptions and nothing supplies them. Add a
class that implements IDesignTimeDbContextFactory, or register the context in a
host, and the command works.
The factory is the direct fix for a console app or any project without a host: a dozen lines that tell the tools which provider and connection string to use at design time. Your runtime code does not change.
The error
Unable to create a 'DbContext' of type 'ClinicDb'. The exception 'Unable to resolve service for type 'Microsoft.EntityFrameworkCore.DbContextOptions`1[EfLabCli.ClinicDb]' while attempting to activate 'EfLabCli.ClinicDb'.' was thrown while attempting to create an instance. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
Why it happens
Migrations are generated from the model, so the tools need a live instance of your
DbContext before they can do anything. The context here has one constructor,
ClinicDb(DbContextOptions<ClinicDb> options), which is the normal shape for a
context used with dependency injection. The console app builds those options by hand in
Program.cs and calls new ClinicDb(options), but the tools do not run
that code. Adding --verbose shows where they looked:
Finding IDesignTimeDbContextFactory implementations...
Finding DbContext classes in the project...
Found DbContext 'ClinicDb'.
Finding application service provider in assembly 'EfLabCli'...
Finding Microsoft.Extensions.Hosting service provider...
No static method 'CreateHostBuilder(string[])' was found on class 'Program'.
No application service provider was found.
No factory, no host, so the last resort is to activate ClinicDb directly, and
that fails on the options parameter. The message is long because it nests the dependency
injection error inside the EF one; the inner part is the real cause.
The fix
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
namespace EfLabCli;
public class ClinicDbFactory : IDesignTimeDbContextFactory<ClinicDb>
{
public ClinicDb CreateDbContext(string[] args)
{
var options = new DbContextOptionsBuilder<ClinicDb>()
.UseNpgsql("Host=127.0.0.1;Port=5497;Database=e2;Username=fixes;Password=fixes")
.Options;
return new ClinicDb(options);
}
}
With this file in the project, the same dotnet ef migrations add Init printed
Done. and created the migration. The tools find the factory first and never try
the other routes. In a real project read the connection string from configuration or an
environment variable instead of a literal; generating a migration does not connect to the
database, but dotnet ef database update uses the same factory and does.
The other supported pattern is a host. With the factory removed and Program.cs
rewritten around the generic host, the tools reported
Using application service provider from Microsoft.Extensions.Hosting. and the
migration was created:
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddDbContext<ClinicDb>(o =>
o.UseNpgsql("Host=127.0.0.1;Port=5497;Database=e2;Username=fixes;Password=fixes"));
using var host = builder.Build();
The tools run your Program up to builder.Build() and take the context
from the container, which is why ASP.NET Core projects rarely see this error. Pick the host if
the app already uses dependency injection; pick the factory if it does not.
How it was reproduced
A console app from dotnet new console with Microsoft.EntityFrameworkCore 10.0.12,
Microsoft.EntityFrameworkCore.Design 10.0.12 and Npgsql.EntityFrameworkCore.PostgreSQL 10.0.3,
a ClinicDb context with only the options constructor, and the global
dotnet-ef tool 10.0.0. Running dotnet ef migrations add Init in the
project folder printed the error above. The host check added Microsoft.Extensions.Hosting
10.0.12. .NET SDK 10.0.401 on Windows.
Frequently asked
- How do I fix Unable to create a DbContext of type in dotnet ef?
- Give the EF tools a way to build the context. Add a class implementing IDesignTimeDbContextFactory<TContext> that creates the options and returns the context, or register the context with AddDbContext in a host that Program builds. Either one lets migrations add succeed.
- Where does IDesignTimeDbContextFactory go?
- Put it in the project that contains the DbContext. The tools search for a factory before they try anything else, and once they find it they use it for every design-time command, including migrations add and database update.
- Why does dotnet ef not use the DbContext I create in Program.cs?
- The tools only run Program far enough to get a built host and its service provider. Code that creates DbContextOptions by hand and calls new on the context is never reached, so the tools cannot see those options.
More decoded errors in the Fixes category. Once the migration
exists, paste the output of dotnet ef migrations script into the
EF Core migration SQL explainer to read what it will
do before you apply it.