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.
The dbContextOptions carries the configuration information needed to configure the DbContext. The dbContextOptions can also be configured using the OnConfiguring method. This method gets the DbContextOptionsBuilder as its argument. It is then used to create the dbContextOptions.
The Entity Framework Core tools help with design-time development tasks. They're primarily used to manage Migrations and to scaffold a DbContext and entity types by reverse engineering the schema of a database.
You can use EF Core in APIs and applications that require the full . NET Framework, as well as those that target only the cross-platform .
As you can see we can also configure options such as which provider we are using… but we don’t have to do this here, we can defer this to the OnConfiguring method in our DbContext class if we wish. You might also be interested in...
In Startup.cs (Configure Services) public void ConfigureServices (IServiceCollection services) { //Some Code services.AddDbContext<LibraryContext> (); //Some Code } and then in your DbContext class instead on passing the DbContextOptions to your base class, configure them as follows.
The code above will register EFContext as a scoped service which means it is tied to the request which is ideal in a web application. As you can see we can also configure options such as which provider we are using… but we don’t have to do this here, we can defer this to the OnConfiguring method in our DbContext class if we wish.
MVC is throwing the exception as it cannot find what class implements EFContext when it is attempting to create an instance of the CustomersController class.
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
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>());
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With