UseInMemoryDatabase with UseInternalServiceProvider. No database provider configured
Unfortunately, the solution is hair-tearingly simple. However, there seems to be very little documentation about using dependency injection with the in-memory database functionality. It appears to be one or the other. Hopefully this question will provide help for future people misfortunate enough to run into this.
I downloaded the EntityFramework source to investigate, and found that calling UseInMemoryDatabase
creates an extension InMemoryOptionsExtension
which itself will add to the service provider, namely:
public virtual void ApplyServices(IServiceCollection services)
{
Check.NotNull(services, nameof(services));
services.AddEntityFrameworkInMemoryDatabase();
}
And the solution is as simple as it looks:
public class TestStartup : Startup
{
public TestStartup(IHostingEnvironment env) : base(env)
{
}
public override void ConfigureServices(IServiceCollection services)
{
services
.AddEntityFrameworkInMemoryDatabase()
.AddDbContext<APIContext>((sp, options) =>
{
options.UseInMemoryDatabase().UseInternalServiceProvider(sp);
});
base.ConfigureServices(services);
}
}
Rob
Author of Rodgort - A project designed to make managing burnination, synonym and merge requests easier on Stack Overflow Advanced Flagging - A userscript to aid with moderation. Higgs - A work in progress to provide web interfaces for bots in SOBotics
Updated on June 19, 2022Comments
-
Rob almost 2 years
I'm having trouble injecting a custom
IAsyncQueryProvider
when using EntityFrameworkCore. To be more precise.. I am having trouble injecting the provider when using the in memory database functionality provided. Using a default provider (SqlServer), all works fine.Here's my global
Startup.cs
private void ConfigureEntityFrameworkWithSecurity(IServiceCollection services) { services .AddEntityFramework() .AddEntityFrameworkSqlServer() .AddScoped<IAsyncQueryProvider, CustomEntityProvider>() .AddDbContext<APIContext>((sp, options) => { options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")) .UseInternalServiceProvider(sp); }); }
This works flawlessly, and I can put a breakpoint within
CustomEntityProvider
to verify that it is indeed being injected. At the moment,CustomEntityProvider
simply implementsIAsyncQueryProvider
, and simply passes through the request. There is no logic contained within it.When I'm running a test, I configure the webhost to use a different
Startup
file:public class TestStartup : Startup { public TestStartup(IHostingEnvironment env) : base(env) { } public override void ConfigureServices(IServiceCollection services) { services .AddDbContext<APIContext>((sp, options) => { options.UseInMemoryDatabase() .UseInternalServiceProvider(sp); }); base.ConfigureServices(services); } }
Running a test with
TestStartup
yields the error:System.InvalidOperationException : 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.
And
APIContext
is correctly defined:public class APIContext : DbContext { public APIContext(DbContextOptions<APIContext> options) : base(options) { } ... }
Removing
UseInternalServiceProvider
fromTestStartup
works correctly - however, I don't want my tests to hit an actual database. Further, I would expectUseInMemoryDatabase
to automatically inject dependencies into the service provider - as it works perfectly fine by itself.The error is confusing because the in memory database is the provider I want to use.