Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 70 additions & 1 deletion entity-framework/core/dbcontext-configuration/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: DbContext Lifetime, Configuration, and Initialization - EF Core
description: Patterns for creating and managing DbContext instances with or without dependency injection
author: SamMonoRT
ms.date: 11/07/2020
ms.date: 09/30/2025
uid: core/dbcontext-configuration/index
---

Expand Down Expand Up @@ -90,6 +90,75 @@ The final result is an `ApplicationDbContext` instance created for each request

Read further in this article to learn more about configuration options. See [Dependency injection in ASP.NET Core](/aspnet/core/fundamentals/dependency-injection) for more information.

<a name="configuredbcontext"></a>

## ConfigureDbContext for configuration composition

Starting with EF Core 9.0, you can use <xref:Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.ConfigureDbContext*> to apply additional configuration to a `DbContext` either before or after the `AddDbContext` call. This is particularly useful for composing non-conflicting configuration in reusable components or tests.

### Basic ConfigureDbContext usage

`ConfigureDbContext` allows you to add configuration in a reusable library or component without replacing the entire provider configuration:

<!--
var services = new ServiceCollection();

services.ConfigureDbContext<BlogContext>(options =>
options.EnableSensitiveDataLogging()
.EnableDetailedErrors());

services.AddDbContext<BlogContext>(options =>
options.UseInMemoryDatabase("BasicExample"));

var serviceProvider = services.BuildServiceProvider();
-->
[!code-csharp[BasicConfigureDbContext](../../../samples/core/Miscellaneous/ConfiguringDbContext/ConfigureDbContextSample.cs?name=BasicConfigureDbContext)]

### Provider-specific configuration without connection strings

To apply provider-specific configuration you can use provider-specific configuration methods without supplying the connection string. The SQL Server provider also includes `ConfigureSqlEngine` for this case. See [SQL Server-specific batching behavior](xref:core/providers/sql-server/misc#configuresqlengine) for more information.

<!--
var services = new ServiceCollection();

services.ConfigureDbContext<BlogContext>(options =>
options.UseSqlServer(sqlOptions =>
sqlOptions.EnableRetryOnFailure()));

services.AddDbContext<BlogContext>(options =>
options.UseSqlServer("connectionString"));

var serviceProvider = services.BuildServiceProvider();
-->
[!code-csharp[ProviderSpecificConfiguration](../../../samples/core/Miscellaneous/ConfiguringDbContext/ConfigureDbContextSample.cs?name=ProviderSpecificConfiguration)]

### ConfigureDbContext and AddDbContext precedence

When both `ConfigureDbContext` and `AddDbContext` are used, or when multiple calls to these methods are made, the configuration is applied in the order the methods are called, with later calls taking precedence for conflicting options.

For non-conflicting options (like adding logging, interceptors, or other settings), all configurations are composed together:

<!--
var services = new ServiceCollection();

services.ConfigureDbContext<BlogContext>(options =>
options.LogTo(Console.WriteLine));

services.AddDbContext<BlogContext>(options =>
options.UseInMemoryDatabase("CompositionExample"));

services.ConfigureDbContext<BlogContext>(options =>
options.EnableSensitiveDataLogging());

var serviceProvider = services.BuildServiceProvider();
-->
[!code-csharp[ConfigurationComposition](../../../samples/core/Miscellaneous/ConfiguringDbContext/ConfigureDbContextSample.cs?name=ConfigurationComposition)]

For conflicting options, the last configuration wins. See [breaking changes in EF Core 8.0](xref:core/what-is-new/ef-core-8.0/breaking-changes#AddDbContext) for more information about this behavior change.

> [!NOTE]
> Configuring a different provider will not remove the previous provider configuration. This can lead to errors when creating the context. To completely replace the provider, you need to remove the context registration and re-add it, or create a new service collection.

<!-- See also [Using Dependency Injection](TODO) for advanced dependency injection configuration with EF Core. -->

## Basic DbContext initialization with 'new'
Expand Down
39 changes: 35 additions & 4 deletions entity-framework/core/what-is-new/ef-core-8.0/breaking-changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -627,19 +627,50 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)

#### Old behavior

Previously, when multiple calls to `AddDbContext`, `AddDbContextPool`, `AddDbContextFactory` or `AddPooledDbContextFactor` were made with the same context type but conflicting configuration, the first one won.
Previously, when multiple calls to `AddDbContext`, `AddDbContextPool`, `AddDbContextFactory` or `AddPooledDbContextFactory` were made with the same context type but conflicting configuration, the first one won.

#### New behavior

Starting with EF Core 8.0, the configuration from the last call one will take precedence.
Starting with EF Core 8.0, the configuration from the last call will take precedence.

#### Why

This was changed to be consistent with the new method `ConfigureDbContext` that can be used to add configuration either before or after the `Add*` methods.
This was changed to be consistent with the new method `ConfigureDbContext`, that enables configuration composability for non-conflicting configurations. See [DbContext configuration](xref:core/dbcontext-configuration/index#configuredbcontext) for more information.

#### Mitigations

Reverse the order of `Add*` calls.
If your application depends on the previous behavior where the first registration wins, you have several options:

1. **Reorder your registrations**: Place the registration with the configuration you want to use last:

```csharp
services.AddDbContext<MyContext>(options =>
options.UseSqlServer("connection1")); // This will be ignored now

services.AddDbContext<MyContext>(options =>
options.UseSqlServer("connection2")); // This will be used
```

2. **Remove previous registrations**: If possible, remove the conflicting registration.

3. **Use conditional registration**: Check if the service is already registered before adding:

```csharp
if (!services.Any(d => d.ServiceType == typeof(DbContextOptions<MyContext>)))
{
services.AddDbContext<MyContext>(options =>
options.UseSqlServer("connection"));
}
```

4. **Use the new `ConfigureDbContext` method**: This allows you to configure options without registering the context itself. See [DbContext configuration](xref:core/dbcontext-configuration/index#configuredbcontext) for more information:

```csharp
services.ConfigureDbContext<MyContext>(options =>
options.UseSqlServer("connection"));

services.AddDbContext<MyContext>(); // Register the context without configuration
```

<a name="attributeConventionBase"></a>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#nullable enable

using System;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

namespace ConfigureDbContextSample;

public class BlogContext : DbContext
{
public BlogContext(DbContextOptions<BlogContext> options) : base(options)
{
}

public DbSet<Blog> Blogs => Set<Blog>();
}

public class Blog
{
public int Id { get; set; }
public required string Title { get; set; }
public string? Content { get; set; }
}

public static class ConfigureDbContextSample
{
public static void Run()
{
BasicConfigureDbContextExample();
ProviderSpecificConfigurationExample();
ConfigurationCompositionExample();
}

private static void BasicConfigureDbContextExample()
{
Console.WriteLine("=== Basic ConfigureDbContext Example ===");

#region BasicConfigureDbContext
var services = new ServiceCollection();

services.ConfigureDbContext<BlogContext>(options =>
options.EnableSensitiveDataLogging()
.EnableDetailedErrors());

services.AddDbContext<BlogContext>(options =>
options.UseInMemoryDatabase("BasicExample"));
#endregion

var serviceProvider = services.BuildServiceProvider();
using var scope = serviceProvider.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<BlogContext>();

Console.WriteLine($"Context configured with provider: {context.Database.ProviderName}");
Console.WriteLine();
}

private static void ProviderSpecificConfigurationExample()
{
Console.WriteLine("=== Provider-Specific Configuration Example ===");

#region ProviderSpecificConfiguration
var services = new ServiceCollection();

services.ConfigureDbContext<BlogContext>(options =>
options.UseSqlServer(sqlOptions =>
sqlOptions.EnableRetryOnFailure()));

services.AddDbContext<BlogContext>(options =>
options.UseSqlServer("connectionString"));
#endregion

var serviceProvider = services.BuildServiceProvider();
Console.WriteLine("Provider-specific configuration applied");
Console.WriteLine();
}

private static void ConfigurationCompositionExample()
{
Console.WriteLine("=== Configuration Composition Example ===");

#region ConfigurationComposition
var services = new ServiceCollection();

services.ConfigureDbContext<BlogContext>(options =>
options.LogTo(Console.WriteLine));

services.AddDbContext<BlogContext>(options =>
options.UseInMemoryDatabase("CompositionExample"));

services.ConfigureDbContext<BlogContext>(options =>
options.EnableSensitiveDataLogging());
#endregion

var serviceProvider = services.BuildServiceProvider();
using var scope = serviceProvider.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<BlogContext>();

Console.WriteLine($"Context configured with provider: {context.Database.ProviderName}");
Console.WriteLine();
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace />
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
</ItemGroup>

</Project>
Loading