0

I've just started work on an experimental project using ASP.net 5, MVC6 and Entity Framework 7. I have ASP.Net Identity working fine, but then tried to add some of my own data to the DbContext and hit this problem. EF7 reports:

An unhandled exception occurred while processing the request.

InvalidOperationException: No database providers are configured. Configure a database provider by overriding OnConfiguring in your DbContext class or in the AddDbContext method when setting up services.

Microsoft.Data.Entity.Internal.DatabaseProviderSelector.SelectServices(ServiceProviderSource providerSource) Stack Query Cookies Headers

InvalidOperationException: No database providers are configured. Configure a database provider by overriding OnConfiguring in your DbContext class or in the AddDbContext method when setting up services.

Here's my configuration method:

    public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddApplicationInsightsTelemetry(Configuration);

        services.AddEntityFramework()
            .AddSqlServer()
            .AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));

        services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

        services.AddMvc();

        // Add application services.
        services.AddTransient<IEmailSender, AuthMessageSender>();
        services.AddTransient<ISmsSender, AuthMessageSender>();

        services.AddTransient<ApplicationUnitOfWork>(instance => new ApplicationUnitOfWork());
    }

ApplicationUnitOfWork is a façade over EF7 to reduce tight coupling. Here's the whole thing so far:

public class ApplicationUnitOfWork : IUnitOfWork
    {
    readonly ApplicationDbContext dbContext;

    public ApplicationUnitOfWork()
        {
        dbContext = new ApplicationDbContext();
        Products = new ProductRepository(dbContext);
        }

    public void Dispose() { dbContext.Dispose(); }

    public IUserRepository Users { get; }

    public IRepository<SoftwareProduct> Products { get; }

    public async Task CommitAsync() { await dbContext.SaveChangesAsync(); }

    public void Cancel() { throw new NotImplementedException(); }
    }

Now when I run the web application, I am able to register a user account and log in and EF creates the database, creates the Identity tables and populates them with user data. The products table is also created - so clearly at some level EF is able to use the ApplicationDbContext and find a provider which it uses to create the database and schema.

However when I try to access my Products controller, which uses the ProductsRepository, EF complains - even though ApplicationDbContext is used in both cases and was used to create the database!

So how come? What's special about ASP.net Identity that it can somehow obtain a provider, but my own code can't? What "magic incantation" am I missing?

Tim Long
  • 13,508
  • 19
  • 79
  • 147

1 Answers1

6

its because you are newing it up instead of having it injected for you. The one you are newing up hasn't been configured. You should change your class to have it passed into the constructor.

DbContext has more than one constructor and you are using the empty one which doesn't configure it.

Better to let it be injected by making your constructor like this:

 public ApplicationUnitOfWork(ApplicationDbContext context)
 {
    dbContext = context;
    Products = new ProductRepository(dbContext);
 }

your code shows that ApplicationDbContext has been registered with the DI, Identity is using the injected one but you are not since you newed it up yourself with the parameterless constructor

you should also register your ApplicationUnitOfWork so it can be injected:

services.AddScoped<ApplicationUnitOfWork, ApplicationUnitOfWork>();
Joe Audette
  • 35,330
  • 11
  • 106
  • 99
  • Let me see if I understand this correctly... you're saying I should never create my own instance of the DbContext, right? And the framework will "just know" how to create it? – Tim Long Feb 27 '16 at 17:49
  • 1
    right, all that services.* code is configuring things in the DI container so the DI will be able to inject it. You use dependency injection all the way down, ie if your controller needs an instance of ApplicationUnitOfWork you should also add that to services and to the constructor of your controller so it can be injected as well – Joe Audette Feb 27 '16 at 17:54
  • 1
    I'm not saying never as there may be edge cases where it would make sense to new up a DbContext yourself, but yes in general you should not create one yourself – Joe Audette Feb 27 '16 at 17:55
  • That's completely in line with how I want to work. In fact, looking at your example, I'm not sure why I didn't already do it that way. I guess it was not transparent to me that the configuration was setting up the D.I. container and I was trying to start simple and expand incrementally. – Tim Long Feb 27 '16 at 18:00
  • 1
    if there is ever a case where you do need to new up a DbContext, you would use a different constructor as shown in [this similar question](http://stackoverflow.com/questions/34589158/dbcontext-cannot-find-database/34613101#34613101) but best not to unless you have a specific reason – Joe Audette Feb 27 '16 at 18:09
  • That nailed it, everything working now. You, sir, are a superstar :) – Tim Long Feb 27 '16 at 18:11