Skip to content

Add RemoveExtension and RemoveDbContext APIs for removing provider configuration#37891

Merged
AndriySvyryd merged 6 commits intomainfrom
copilot/add-api-remove-provider-config
Mar 10, 2026
Merged

Add RemoveExtension and RemoveDbContext APIs for removing provider configuration#37891
AndriySvyryd merged 6 commits intomainfrom
copilot/add-api-remove-provider-config

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 9, 2026

Since .NET 9, DbContextOptions<> uses IDbContextOptionsConfiguration<> instances for composition rather than holding configuration directly. This makes replacing a database provider in testing scenarios (e.g., swapping SQL Server for InMemory) difficult—there's no public API to remove a previously registered provider extension.

New APIs

  • IDbContextOptionsBuilderInfrastructure.RemoveExtension<TExtension>() — removes an extension from the options builder
  • DbContextOptions.WithoutExtension<TExtension>() — immutable counterpart to WithExtension, returns new options without the specified extension; returns this when the extension isn't present and renormalizes ordinals to keep them contiguous
  • IServiceCollection.RemoveDbContext<TContext>(bool removeConfigurationOnly = false) — removes context-specific services from DI (typed options, configuration, factory, pool, scoped lease registrations); when removeConfigurationOnly: true, only strips IDbContextOptionsConfiguration<TContext> registrations. Does not remove the non-generic DbContextOptions forwarding registration since it may belong to a different context.

Usage

Remove a specific provider extension via ConfigureDbContext:

services.ConfigureDbContext<TestContext>(options =>
    ((IDbContextOptionsBuilderInfrastructure)options).RemoveExtension<SqlServerOptionsExtension>());

Or fully replace a context registration in integration tests:

services.RemoveDbContext<ApplicationDbContext>();
services.AddDbContext<ApplicationDbContext>(options =>
    options.UseInMemoryDatabase("TestDb"));

Or remove only the configuration while keeping the context registered:

services.RemoveDbContext<ApplicationDbContext>(removeConfigurationOnly: true);
services.ConfigureDbContext<ApplicationDbContext>(options =>
    options.UseInMemoryDatabase("TestDb"));
Original prompt

This section details on the original issue you should resolve

<issue_title>Add API to remove provider configuration.</issue_title>
<issue_description>After upgrading to .NET 9 I get the following error on db.Database.EnsureCreated(); in the following code:

using (var scope = sp.CreateScope())
{
    var scopedServices = scope.ServiceProvider;
    var db = scopedServices.GetRequiredService<ApplicationDbContext>();
    var logger = scopedServices
        .GetRequiredService<ILogger<CustomWebApplicationFactory<TStartup>>>();

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

    try
    {
        // Seed the database with test data.
        // Utilities.InitializeDbForTests(db);
    }
    catch (Exception ex)
    {
        logger.LogError(ex, "An error occurred seeding the " +
            "database with test messages. Error: {Message}", ex.Message);
    }
}

Image

The exact error:

System.InvalidOperationException
  HResult=0x80131509
  Message=Services for database providers 'Microsoft.EntityFrameworkCore.SqlServer', 'Microsoft.EntityFrameworkCore.InMemory' have been registered in the service provider. Only a single database provider can be registered in a service provider. If possible, ensure that Entity Framework is managing its service provider by removing the call to 'UseInternalServiceProvider'. Otherwise, consider conditionally registering the database provider, or maintaining one service provider per database provider.
  Source=Microsoft.EntityFrameworkCore
  StackTrace:
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.Initialize(IServiceProvider scopedProvider, DbContextOptions contextOptions, DbContext context)
   at Microsoft.EntityFrameworkCore.DbContext.get_ContextServices()
   at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
   at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance()
   at Microsoft.EntityFrameworkCore.Infrastructure.Internal.InfrastructureExtensions.GetService(IInfrastructure`1 accessor, Type serviceType)
   at Microsoft.EntityFrameworkCore.Infrastructure.Internal.InfrastructureExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.get_Dependencies()
   at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.EnsureCreated()
   at SpiderIoT.Test.CustomWebApplicationFactory`1.<>c.<ConfigureWebHost>b__0_0(IServiceCollection services) in C:\Source\SpiderIoT\SpiderIoT.Test\CustomWebApplicationFactory.cs:line 54
   at Microsoft.Extensions.Hosting.HostBuilder.InitializeServiceProvider()
   at Microsoft.Extensions.Hosting.HostBuilder.Build()
   at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.CreateHost(IHostBuilder builder)
   at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.ConfigureHostBuilder(IHostBuilder hostBuilder)
   at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.EnsureServer()
   at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.get_Services()
   at SpiderIoT.Test.APITest..ctor(CustomWebApplicationFactory`1 factory) in C:\Source\SpiderIoT\SpiderIoT.Test\APITest.cs:line 36
   at System.Reflection.MethodBaseInvoker.InvokeWithOneArg(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)

My feeling is that removing the previous ApplicationDbContext is not working properly? This is my code (which was adjusted according to the .NET 9 docs, but is still not working):

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

 services.Remove(dbContextDescriptor);

 var dbConnectionDescriptor = services.SingleOrDefault(
     d => d.ServiceType ==
         typeof(DbConnection));

 services.Remove(dbConnectionDescriptor);

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

After hours of Googling and trying stuff out I'm a bit lost how this should work in .NET 9...</issue_description>

<agent_instructions>Add RemoveDbContext(bool onlyRemoveConfiguration = false)</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@cincuranet You don't want to mix multiple providers with single `DbContext`. Manually removing `IDbContextOptionsConfiguration` works, but you're starting to touch internal infrastructure of EF and the underlying implementation can change in the futur...

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 2 commits March 9, 2026 18:49
…nfiguration

- Add RemoveExtension<TExtension>() to IDbContextOptionsBuilderInfrastructure
- Add WithoutExtension<TExtension>() to DbContextOptions and DbContextOptions<TContext>
- Implement RemoveExtension<TExtension>() in DbContextOptionsBuilder
- Add RemoveDbContext<TContext>(bool removeConfiguration) extension on IServiceCollection
- Add unit tests for all new APIs

Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
…DbContext

Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Copilot AI changed the title [WIP] Add API to remove provider configuration Add RemoveExtension and RemoveDbContext APIs for removing provider configuration Mar 9, 2026
@AndriySvyryd AndriySvyryd marked this pull request as ready for review March 9, 2026 19:29
@AndriySvyryd AndriySvyryd requested a review from a team as a code owner March 9, 2026 19:29
Copilot AI review requested due to automatic review settings March 9, 2026 19:29
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces new public APIs to support removing EF Core provider configuration in .NET 9+ centralized IDbContextOptionsConfiguration<TContext> scenarios, enabling provider swapping (especially in tests) without rebuilding the entire DI setup.

Changes:

  • Add IDbContextOptionsBuilderInfrastructure.RemoveExtension<TExtension>() and underlying options support via DbContextOptions.WithoutExtension<TExtension>().
  • Add IServiceCollection.RemoveDbContext<TContext>(bool removeConfiguration = false) for removing context registrations and/or centralized configuration.
  • Add unit tests covering the new behaviors.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
test/EFCore.Tests/DbContextTest.Services.cs Adds tests for RemoveDbContext behavior (full removal, config-only removal, re-registration).
test/EFCore.Tests/DbContextOptionsTest.cs Adds tests for removing an options extension and for no-op removal.
src/EFCore/Infrastructure/IDbContextOptionsBuilderInfrastructure.cs Adds RemoveExtension<TExtension>() to the builder infrastructure interface.
src/EFCore/Extensions/EntityFrameworkServiceCollectionExtensions.cs Adds RemoveDbContext<TContext>(removeConfiguration: bool) DI helper.
src/EFCore/DbContextOptions.cs Adds DbContextOptions.WithoutExtension<TExtension>() API surface.
src/EFCore/DbContextOptions`.cs Implements WithoutExtension<TExtension>() for DbContextOptions<TContext>.
src/EFCore/DbContextOptionsBuilder.cs Implements RemoveExtension<TExtension>() on the builder infrastructure.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread src/EFCore/DbContextOptions.cs
Comment thread src/EFCore/DbContextOptions`.cs Outdated
Comment thread src/EFCore/Extensions/EntityFrameworkServiceCollectionExtensions.cs
@AndriySvyryd AndriySvyryd marked this pull request as draft March 9, 2026 19:53
…nal check from Equals, remove non-generic DbContextOptions in RemoveDbContext

Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.


You can also share your feedback on Copilot code review. Take the survey.

Comment thread src/EFCore/Infrastructure/IDbContextOptionsBuilderInfrastructure.cs
…ti-context isolation test; fix XML doc

Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
@AndriySvyryd AndriySvyryd marked this pull request as ready for review March 9, 2026 21:04
Copilot AI review requested due to automatic review settings March 9, 2026 21:04
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.


You can also share your feedback on Copilot code review. Take the survey.

Comment thread src/EFCore/DbContextOptions.cs Outdated
Comment thread src/EFCore/DbContextOptions`.cs
Comment thread test/EFCore.Tests/DbContextTest.Services.cs
Comment thread src/EFCore/Extensions/EntityFrameworkServiceCollectionExtensions.cs Outdated
…onOnly, add regression tests

Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
@AndriySvyryd AndriySvyryd enabled auto-merge (squash) March 10, 2026 22:55
@AndriySvyryd AndriySvyryd merged commit 31144c5 into main Mar 10, 2026
12 checks passed
@AndriySvyryd AndriySvyryd deleted the copilot/add-api-remove-provider-config branch March 10, 2026 23:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add API to remove provider configuration.

4 participants