Reputation: 4478
I am trying to access the databse using EF Core 5.0 on an ASP.NET Core project. For the first migration, I overrode the OnConfiguring()
method on the DBContext and updated the database successfully.
For the second migration, I decided to use the dependency injection in ASP.NET Core following the guidelines. Here are the changes I made.
services.AddDbContext
in my Startup.cs
.OnConfiguring()
method from DBContext
.After running dotnet ef migrations add Posts
, I get following error:
Microsoft.EntityFrameworkCore.Design.OperationException:
Unable to create an object of type 'BlogContext'.
For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
If I add the --verbose flag, I get this output:
Build started...
dotnet build blog/app/app.csproj /verbosity:quiet /nologo
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:02.50
Build succeeded.
Finding DbContext classes...
Finding IDesignTimeDbContextFactory implementations...
Finding application service provider in assembly 'app'...
Finding Microsoft.Extensions.Hosting service provider...
No static method 'CreateHostBuilder(string[])' was found on class 'Program'.
No application service provider was found.
Finding DbContext classes in the project...
Found DbContext 'BlogContext'.
Microsoft.EntityFrameworkCore.Design.OperationException: Unable to create an object of type 'BlogContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
---> System.InvalidOperationException: Unable to resolve service for type 'Microsoft.EntityFrameworkCore.DbContextOptions`1[app.Data.BlogContext]' while attempting to activate 'app.Data.BlogContext'.
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters)
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetServiceOrCreateInstance(IServiceProvider provider, Type type)
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.<>c__DisplayClass13_4.<FindContextTypes>b__13()
Unable to create an object of type 'BlogContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
However, the code works as expected when I run the web application, as in the BlogContext
is created and injected into my classes by the DI layer, and I can access the database.
Hence, I am guessing the DI layer is not running as expected when running the dotnet ef migrations add
command.
Here's my code.
// Program.cs
public class Program
{
public static void Main(string[] args)
{
IHostBuilder builder = Host.CreateDefaultBuilder(args)
.UseSerilog()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
IHost host = builder.Build();
host.Run();
}
}
// BlogContext
using app.Models;
using Microsoft.EntityFrameworkCore;
namespace app.Data
{
public class BlogContext : DbContext
{
public DbSet<Post> Posts { get; set; }
public DbSet<Comment> Comments { get; set; }
public BlogContext(DbContextOptions<BlogContext> options) : base(options)
{
}
}
}
// Startup.cs
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public string ConnectionString => Configuration.GetConnectionString("Blog");
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<BlogContext>(opt => { opt.UseSqlite(ConnectionString); });
}
}
Both the Startup
and BlogContext
live in the same project.
Upvotes: 11
Views: 23694
Reputation: 8741
In my experience, better to create a class (in the same project as the context) that implements IDesignTimeDbContextFactory - as described here. That way, there's not guessing as to which code will get used when using the design time tools such as update-database
Upvotes: 13
Reputation: 4478
Thanks to Ivan and Kirk's comments above and reading the entire verbose output, I figured out the problem. Turned out I was not following the correct pattern in Program.cs
.
From the documentation,
The tools first try to obtain the service provider by invoking Program.CreateHostBuilder(), calling Build(), then accessing the Services property.
I had refactored the original Program.cs
by moving CreateHostBuilder()
inside main()
, which broke the ef-core migration.
After modifying the Program.cs
to following it works as expected.
public class Program
{
public static void Main(string[] args)
=> CreateHostBuilder(args).Build().Run();
// EF Core uses this method at design time to access the DbContext
public static IHostBuilder CreateHostBuilder(string[] args)
=> Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(
webBuilder => webBuilder.UseStartup<Startup>());
}
Upvotes: 8