- 
                Notifications
    
You must be signed in to change notification settings  - Fork 2k
 
Document ConfigureDbContext method and AddDbContext precedence changes in EF Core 8.0 #5118
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 4 commits
aed0fbb
              3c2e6f2
              fc3ce37
              5d80627
              c6277c3
              e544d44
              52ec51e
              1072ea3
              fc950c9
              ce6de19
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| 
          
            
          
           | 
    @@ -90,6 +90,96 @@ 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 | ||
| 
         There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This definitely doesn't seem like the first thing to document on this page, above "Basic DbContext initialization with 'new'". IIUC (and as documented), ConfigureDbContext is for reusable libraries/components (like Aspire), and so is not an end-user API. As such it maybe merits a short note at the very bottom, but nothing like this at the very top - this would confuse any beginner user coming here. (FWIW I don't remember any user requesting something like this for tests, as documented - this would have to be a very advanced/elaborate scenario. Even we've managed fine without it.)  | 
||
| 
     | 
||
| Starting with EF Core 9.0, you can use `ConfigureDbContext` to apply additional configuration to a `DbContext` either before or after the `AddDbContext` call. This is particularly useful for composing non-conflicting, non-provider-specific configuration in reusable components or tests. | ||
                
      
                  AndriySvyryd marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| ### Basic ConfigureDbContext usage | ||
| 
     | 
||
| `ConfigureDbContext` allows you to add configuration without replacing the entire provider configuration: | ||
                
      
                  AndriySvyryd marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| ```csharp | ||
| // In a reusable library or component | ||
| services.ConfigureDbContext<ApplicationDbContext>(options => | ||
| options.EnableSensitiveDataLogging() | ||
| .EnableDetailedErrors()); | ||
| 
     | 
||
| // Later, in the application | ||
| services.AddDbContext<ApplicationDbContext>(options => | ||
| options.UseSqlServer(connectionString)); | ||
| ``` | ||
                
      
                  AndriySvyryd marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| Both configurations will be applied - the logging and error settings from `ConfigureDbContext`, and the SQL Server provider from `AddDbContext`. | ||
                
      
                  AndriySvyryd marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| ### Using ConfigureDbContext in reusable components | ||
| 
     | 
||
| `ConfigureDbContext` is especially useful when creating reusable components that need to add configuration without knowing or modifying the database provider: | ||
| 
     | 
||
| ```csharp | ||
| // In a testing utility library | ||
| public static class TestingExtensions | ||
| { | ||
| public static IServiceCollection AddTestingConfiguration<TContext>( | ||
| this IServiceCollection services) | ||
| where TContext : DbContext | ||
| { | ||
| services.ConfigureDbContext<TContext>(options => | ||
| options.EnableSensitiveDataLogging() | ||
| .EnableDetailedErrors() | ||
| .LogTo(Console.WriteLine)); | ||
| 
     | 
||
| return services; | ||
| } | ||
| } | ||
| 
     | 
||
| // In your test | ||
| services.AddTestingConfiguration<ApplicationDbContext>(); | ||
| services.AddDbContext<ApplicationDbContext>(options => | ||
| options.UseInMemoryDatabase("TestDb")); | ||
| ``` | ||
                
      
                  AndriySvyryd marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| ### Provider-specific configuration without connection strings | ||
| 
     | 
||
| When you need to apply provider-specific configuration but don't have the connection string, you can use provider-specific configuration methods like `ConfigureSqlEngine`: | ||
                
      
                  AndriySvyryd marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| ```csharp | ||
| // Configure SQL Server-specific options without knowing the connection string | ||
| services.ConfigureDbContext<ApplicationDbContext>(options => | ||
| options.UseSqlServer(sqlOptions => | ||
| sqlOptions.EnableRetryOnFailure() | ||
| .CommandTimeout(30))); | ||
| 
     | 
||
| // Later, add the context with the connection string | ||
| services.AddDbContext<ApplicationDbContext>(options => | ||
| options.UseSqlServer(connectionString)); | ||
| ``` | ||
| 
     | 
||
| ### 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: | ||
| 
     | 
||
| ```csharp | ||
| // First: add logging | ||
| services.ConfigureDbContext<ApplicationDbContext>(options => | ||
| options.LogTo(Console.WriteLine)); | ||
| 
     | 
||
| // Second: add the provider | ||
| services.AddDbContext<ApplicationDbContext>(options => | ||
| options.UseSqlServer(connectionString)); | ||
| 
     | 
||
| // Third: add sensitive data logging | ||
| services.ConfigureDbContext<ApplicationDbContext>(options => | ||
| options.EnableSensitiveDataLogging()); | ||
| 
     | 
||
| // Result: All three configurations are applied | ||
| ``` | ||
| 
     | 
||
| For conflicting options (like specifying different database providers), 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. | ||
                
      
                  AndriySvyryd marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| <!-- See also [Using Dependency Injection](TODO) for advanced dependency injection configuration with EF Core. --> | ||
| 
     | 
||
| ## Basic DbContext initialization with 'new' | ||
| 
          
            
          
           | 
    ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
                
      
                  AndriySvyryd marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFramework>net8.0</TargetFramework> | ||
| <Nullable>enable</Nullable> | ||
| </PropertyGroup> | ||
| 
     | 
||
| <ItemGroup> | ||
| <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" /> | ||
| <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="9.0.0" /> | ||
| <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" /> | ||
| <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" /> | ||
| <PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.0" /> | ||
| </ItemGroup> | ||
| 
     | 
||
| </Project> | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,134 @@ | ||
| using System; | ||
| using Microsoft.EntityFrameworkCore; | ||
| using Microsoft.Extensions.Configuration; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
| using Microsoft.Extensions.Hosting; | ||
| 
     | 
||
| namespace ConfigureDbContextSample; | ||
| 
     | 
||
| #region BlogContext | ||
                
      
                  AndriySvyryd marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 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; } | ||
| } | ||
| #endregion | ||
| 
     | 
||
| #region TestingExtensions | ||
| public static class TestingExtensions | ||
| { | ||
| public static IServiceCollection AddTestingConfiguration<TContext>( | ||
| this IServiceCollection services) | ||
| where TContext : DbContext | ||
| { | ||
| services.ConfigureDbContext<TContext>(options => | ||
| options.EnableSensitiveDataLogging() | ||
| .EnableDetailedErrors() | ||
| .LogTo(Console.WriteLine)); | ||
| 
     | 
||
| return services; | ||
| } | ||
| } | ||
| #endregion | ||
| 
     | 
||
| public class Program | ||
| { | ||
| public static void Main(string[] args) | ||
                
      
                  AndriySvyryd marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| { | ||
| BasicConfigureDbContextExample(); | ||
| ReusableComponentExample(); | ||
| ConfigurationCompositionExample(); | ||
| } | ||
| 
     | 
||
| private static void BasicConfigureDbContextExample() | ||
| { | ||
| Console.WriteLine("=== Basic ConfigureDbContext Example ==="); | ||
| 
     | 
||
| #region BasicConfigureDbContext | ||
| var services = new ServiceCollection(); | ||
| 
     | 
||
| // Configure non-provider-specific options | ||
| services.ConfigureDbContext<BlogContext>(options => | ||
| options.EnableSensitiveDataLogging() | ||
| .EnableDetailedErrors()); | ||
| 
     | 
||
| // Add the context with provider configuration | ||
| services.AddDbContext<BlogContext>(options => | ||
| options.UseInMemoryDatabase("BasicExample")); | ||
| 
     | 
||
| var serviceProvider = services.BuildServiceProvider(); | ||
| #endregion | ||
                
      
                  AndriySvyryd marked this conversation as resolved.
               
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| using var scope = serviceProvider.CreateScope(); | ||
| var context = scope.ServiceProvider.GetRequiredService<BlogContext>(); | ||
| 
     | 
||
| Console.WriteLine($"Context configured with provider: {context.Database.ProviderName}"); | ||
| Console.WriteLine("ConfigureDbContext was called before AddDbContext"); | ||
| Console.WriteLine(); | ||
| } | ||
| 
     | 
||
| private static void ReusableComponentExample() | ||
| { | ||
| Console.WriteLine("=== Reusable Component Example ==="); | ||
| 
     | 
||
| #region ReusableComponent | ||
| var services = new ServiceCollection(); | ||
| 
     | 
||
| // Use the testing extension method | ||
| services.AddTestingConfiguration<BlogContext>(); | ||
| 
     | 
||
| // Add the context with provider | ||
| services.AddDbContext<BlogContext>(options => | ||
| options.UseInMemoryDatabase("TestDb")); | ||
| 
     | 
||
| var serviceProvider = services.BuildServiceProvider(); | ||
| #endregion | ||
                
      
                  AndriySvyryd marked this conversation as resolved.
               
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| using var scope = serviceProvider.CreateScope(); | ||
| var context = scope.ServiceProvider.GetRequiredService<BlogContext>(); | ||
| 
     | 
||
| Console.WriteLine($"Context configured for testing with provider: {context.Database.ProviderName}"); | ||
| Console.WriteLine("Testing configuration added via extension method"); | ||
| Console.WriteLine(); | ||
| } | ||
| 
     | 
||
| private static void ConfigurationCompositionExample() | ||
| { | ||
| Console.WriteLine("=== Configuration Composition Example ==="); | ||
| 
     | 
||
| #region ConfigurationComposition | ||
| var services = new ServiceCollection(); | ||
| 
     | 
||
| // First: add logging | ||
| services.ConfigureDbContext<BlogContext>(options => | ||
| options.LogTo(Console.WriteLine)); | ||
| 
     | 
||
| // Second: add the provider | ||
| services.AddDbContext<BlogContext>(options => | ||
| options.UseInMemoryDatabase("CompositionExample")); | ||
| 
     | 
||
| // Third: add sensitive data logging | ||
| services.ConfigureDbContext<BlogContext>(options => | ||
| options.EnableSensitiveDataLogging()); | ||
| 
     | 
||
| var serviceProvider = services.BuildServiceProvider(); | ||
| #endregion | ||
                
      
                  AndriySvyryd marked this conversation as resolved.
               
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| using var scope = serviceProvider.CreateScope(); | ||
| var context = scope.ServiceProvider.GetRequiredService<BlogContext>(); | ||
| 
     | 
||
| Console.WriteLine($"Context configured with provider: {context.Database.ProviderName}"); | ||
| Console.WriteLine("All three configurations were composed together"); | ||
| Console.WriteLine(); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.