Tutorials C# & .NET 8 Architect Mastery
Dependency Injection (DI): Lifetime management and Captive Dependencies
On this page
Mastering DI Lifetimes
Dependency Injection is the backbone of modern .NET. But if you don't understand Lifetimes, you will create subtle memory leaks and thread-safety bugs that are almost impossible to find.
1. The Three Lifetimes
- Transient: A new instance every time it's requested. Good for lightweight, stateless services.
- Scoped: One instance per HTTP request. Mandatory for Entity Framework DbContexts.
- Singleton: One instance for the life of the app. Good for caches and configs.
2. Captive Dependencies
This is a senior-level mistake. A Captive Dependency occurs when a 'Longer-lived' service holds onto a 'Shorter-lived' service. Example: A **Singleton** service takes a **Scoped** service in its constructor. The Scoped service is now 'Captured' and will live forever. If that Scoped service is a DbContext, you will eventually have a database connection leak that crashes production.
4. Interview Mastery
Q: "How do you solve a Captive Dependency if you truly need a Scoped service in a Singleton?"
Architect Answer: "You use the **IServiceScopeFactory**. Instead of injecting the Scoped service directly, you inject the factory. Inside the Singleton's method, you call `factory.CreateScope()`. You can then resolve the Scoped service from that temporary scope using a `using` block. This ensures the Scoped service is correctly disposed of as soon as your method is finished, while the Singleton continues to live on."