Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Override EF Core DbContext in ASP.NET Core WebApplicationFactory

I have a ASP.NET Core 2.2 WebApi project which uses also EF Core 2.2. The project is tested via integration tests with WebApplicationFactory<T>.

I tried to migrate the the web api project to netcore/aspnetcore 3 which worked out very well. What I've stumbled across is migrating the tests.

I have following code which worked in aspnetcore 2.2:

    public class MyServiceWebHostFactory : WebApplicationFactory<Service.Startup>
    {
        protected override void ConfigureWebHost(IWebHostBuilder builder)
        {   
            builder.ConfigureServices(services =>
            {
                var serviceProvider = new ServiceCollection()
                                   .AddEntityFrameworkInMemoryDatabase()
                                   .BuildServiceProvider();

                services.AddDbContext<MyContext>((options, context) =>
                {
                    context.UseInMemoryDatabase("MyDb")
                           .UseInternalServiceProvider(serviceProvider);
                });

                var sp = services.BuildServiceProvider();

                using var scope = sp.CreateScope();

                var scopedServices = scope.ServiceProvider;

                // try to receive context with inmemory provider:
                var db = scopedServices.GetRequiredService<MyContext>();

                // more code...

                // Ensure the database is created.
                //db.Database.EnsureCreated();

                // more code...
            });
        }
    }

It replaces the EF Core DbContext with a DbContext using the InMemoryProvider.

After migrating to 3.0 it isn't replaced anymore. I always receive the DBContext with SQL Server configured.

If I remove the services.AddDbContext<MyContext>(options => options.UseSqlServer(connectionString)) call in ConfigureServices of the application (Service.Startup) it works but this isn't a solution.

I also tried a services.RemoveAll(typeof(MyContext)) before registering the inmemory context which doesn't work either.

like image 852
pr177 Avatar asked Oct 14 '19 11:10

pr177


People also ask

How do I dispose of DbContext in EF core?

When the controller is being disposed, call dispose on your repository and that should dispose the context. If you are using a service layer and not talking to the repository directly from the controller, then call dispose on the service which will call dispose on repo which will dispose the context.

What is WebApplicationFactory?

WebApplicationFactory provides multiple ways to customise your application in integration tests, but at it's core, it provides a way to run your application's Host instance in memory.

Can we have more than one DbContext?

"More than one DbContext was found. Specify which one to use. Use the '-Context' parameter for PowerShell commands and the '--context' parameter for dotnet commands."

Should DbContext be scoped or singleton?

Popular Answer. DbContext should not be used as a singleton because it is holding a connection object which cannot be used by multiple threads at the same time. You will run into errors if two requests try to use it at the same time. If your service depends on the context, the service cannot be a singleton.


1 Answers

The updated documentation at https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-3.1 might be able to help. Key fragment change is to remove the previous context service registration:

// Remove the app's ApplicationDbContext registration.
var descriptor = services.SingleOrDefault(
    d => d.ServiceType ==
        typeof(DbContextOptions<ApplicationDbContext>));

if (descriptor != null)
{
    services.Remove(descriptor);
}

// Add ApplicationDbContext using an in-memory database for testing.
services.AddDbContext<ApplicationDbContext>(options =>
{
    options.UseInMemoryDatabase("InMemoryDbForTesting");
});

// Build the service provider.
var sp = services.BuildServiceProvider();
like image 200
eugenecp Avatar answered Oct 03 '22 06:10

eugenecp