🚀 EF Core Tip — DbContext vs IDbContextFactory
When to Use It — and When NOT to Use It
DbContext is one of the most important abstractions in EF Core.
IDbContextFactory<TContext> exists to solve very specific problems.
Using the wrong one leads to:
- Hidden bugs
- Lifetime issues
- Threading problems
- “Works locally, fails in prod”
Let’s clear this up.
🧠 The Core Difference
DbContext→ Scoped, request-based unit of workIDbContextFactory<T>→ Creates DbContext instances on demand
They serve different lifetimes and execution models.
1️⃣ DbContext — The Default (and Correct Choice Most of the Time)
services.AddDbContext<AppDbContext>();
public class OrdersService { public OrdersService(AppDbContext db) { _db = db; } }
✅ When DbContext is the right choice
- ASP.NET Core request pipelines
- Web APIs & MVC controllers
- Typical CRUD operations
- Transactional workflows
- Clean Architecture application services
👍 Why it works so well
- Scoped per request
- Change tracking works as intended
- Transaction boundaries are clear
- Integrated with DI and middleware
👉 This should be your default choice.
2️⃣ IDbContextFactory<T> — For On-Demand & Non-Request Scenarios
services.AddDbContextFactory<AppDbContext>();
public class ReportGenerator { private readonly IDbContextFactory<AppDbContext> _factory; public async Task GenerateAsync() { await using var db = await _factory.CreateDbContextAsync(); // independent DbContext instance } }
✅ When IDbContextFactory makes sense
- Background services (IHostedService)
- Long-running jobs
- Parallel processing
- Blazor WebAssembly
- Scenarios outside
- HTTP request scope
👍 What it solves
- No scoped lifetime dependency
- Thread-safe DbContext creation
- Explicit ownership & disposal
- Avoids “Cannot consume scoped service” errors
⚠️ When NOT to Use IDbContextFactory
❌ Injecting it into controllers
❌ Using it for normal CRUD
❌ Creating multiple contexts per request
❌ Replacing scoped DbContext everywhere “just in case”
This leads to:
- Broken transactions
- Duplicate database connections
- Inconsistent state
- Harder debugging
IDbContextFactoryis not a better DbContext — it’s a different tool.
⚖️ Side-by-Side Comparison
| Concern | DbContext | IDbContextFactory |
|---|---|---|
| Lifetime | Scoped | On-demand |
| Transaction scope | Natural | Manual |
| Change tracking | Cohesive | Per instance |
| Thread safety | ❌ | ✅ |
| Background jobs | ❌ | ✅ |
| Web requests | ✅ | ⚠️ |
🧠 The Most Common Anti-Pattern
public class OrdersController { public OrdersController(IDbContextFactory<AppDbContext> factory) { _factory = factory; } }
This defeats EF Core’s unit-of-work model and introduces subtle bugs.
If you’re inside a request → use DbContext.
🏗️ Rule of Thumb (Memorize This)
- Inside an HTTP request →
DbContext - Outside an HTTP request →
IDbContextFactory - Need transactions across operations →
DbContext - Need parallel / isolated work →
IDbContextFactory
If you don’t have a clear reason to use the factory — you probably shouldn’t.
🎯 Final Takeaway
DbContext is a unit of work.
IDbContextFactory is a unit-of-work factory.
They are not interchangeable.
EF Core works best when you respect lifetime boundaries.
Use the right tool — and EF Core will behave exactly as designed.
#dotnet #csharp #efcore #dbcontext #softwarearchitecture #cleancode #backend
