EF Core 2.1 - No database provider has been configured for this DbContext

asp.net-core-2.1 c# ef-core-2.1 ef-migrations entity-framework-core

Question

I have ASP.Net Core 2.1 with EF Core 2.1. This is how my DbContext class looks like

app.DAL.EF -> Layer

using app.domain;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.Extensions.Configuration;
using System;
using System.IO;

namespace app.EF
{
 public class MyAppContext : DbContext
 {
    public MyAppContext(DbContextOptions<MyAppContext> options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.ApplyConfiguration(new CustomerConfiguration());
        modelBuilder.HasDefaultSchema("app");
        base.OnModelCreating(modelBuilder);
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        base.OnConfiguring(optionsBuilder);
    }

    public DbSet<Customer> Customers { get; set; }
 }

   public class MyAppContextConfiguration : IDesignTimeDbContextFactory<MyAppContext>
   {
    public MyAppContext CreateDbContext(string[] args)
    {
        IConfigurationRoot configuration = new ConfigurationBuilder()
                                            .SetBasePath(Directory.GetCurrentDirectory())
                                            .AddJsonFile("appsettings.json", optional: false, true)
                                            .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT ") ?? "Production" }.json", optional: true)
                                            .Build();

        var optionsBuilder = new DbContextOptionsBuilder<MyAppContext>();
        //optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
        var dbConString = configuration.GetConnectionString("ITMDbConnection");

        optionsBuilder.UseSqlServer(dbConString);

        return new MyAppContext(optionsBuilder.Options);
    }
}

public class CustomerConfiguration : IEntityTypeConfiguration<Customer>
{
    public void Configure(EntityTypeBuilder<Customer> builder)
    {
        builder.HasKey(x => x.Id);
    }
}}

app.DI -> Layer

  public static class Factory
  {
    public static void Initialize(ref IServiceCollection services)
    {
        //services.AddTransient<MyAppContext>();
        services.AddDbContext<MyAppContext>(options =>
        {

        });
        //services.AddTransient<MyAppContextConfiguration>();
        services.AddTransient<ICustomerRepository, CustomerRepository>();
    }
}

app.API -> Layer

 namespace app.api
 {
 public class Startup
 {
     public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        Factory.Initialize(ref services);
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseMvc();
    }
}}

When running Add-Migration DbInit from Package Manager Console, throwing the below error

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 object in its constructor and passes it to the base constructor for DbContext.

error

Thanks!

1
0
3/4/2020 10:19:34 AM

Popular Answer

The error is clear - the provider and connection are never configured. All this code could be replaced with this context :

public class MyAppContext : DbContext
 {
    public DbSet<Customer> Customers { get; set; }

    public MyAppContext(){}

    public MyAppContext(DbContextOptions<MyAppContext> options)
        :base(options)
    {}

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        //The base method is empty
        modelBuilder.HasDefaultSchema("app");
    }
 }

And a call to AddDbContext inside ConfigureServices :


 public class Startup
 {
     public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<MyAppContext>(options =>
        {
            var dbConString = Configuration.GetConnectionString("ITMDbConnection");
            options.UseSqlServer(dbConString);
        });


        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

    ....

}

Most applications have more than one DbContext though. One option would be to add another method to Startup.cs to register them. For more complex applications, eg applications composed of different domains/modules/subsystems/projects, a better idea would be to create extension methods, eg :

public static CustomerDomainExtensions
{
    public static IServicesCollection AddCustomerDomain(this IServicesCollection services,IConfiguration configuration)
    {
        return services.AddCustomerContexts(configuration)
                       .AddRepositories(...)
                       ...;

    }

    public static AddCustomerContexts(this IServicesCollection services,IConfiguration configuration)
    {
        var dbConString = Configuration.GetConnectionString("ITMDbConnection");
        services.AddDbContext<MyAppContext>(options =>
        {
            options.UseSqlServer(dbConString);
        });
        //Add more contexts ...
    }
}

In Startup.cs, this would be called inside ConfigureServices. This is how all Microsoft.Extensions.* classes work, by providing Add and Use extension methods for use in Startup.cs :

public void ConfigureServices(IServiceCollection services)
{
    services.AddCustomerDomain(Configuration);


    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

EDIT

Added a default constructor to the DbContext

0
3/4/2020 9:40:51 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow