🚦 Event Listeners, Processors, and DbContext — Pitfalls & Best Practices - .NET 10
Dependency injection in .NET requires careful consideration of service lifetimes. A common pitfall arises when a singleton service, like an EventListener, directly depends on a scoped service, such as a DbContext. Injecting a scoped DbContext into a singleton EventProcessor leads to the same DbContext instance being reused indefinitely. This stale DbContext can cause issues like outdated data and concurrency errors.A recommended practice is to keep the EventProcessor as a singleton but inject IServiceScopeFactory. This factory allows the singleton processor to create a new scope and obtain a fresh DbContext whenever it needs one. Alternatively, the EventProcessor itself can be registered with a scoped lifetime. In this scenario, a singleton EventListener would use IServiceScopeFactory to create a scope and resolve a scoped EventProcessor for each event it handles.Ultimately, the core principle is to avoid injecting scoped dependencies directly into singletons. If a singleton service requires access to a scoped service, it should obtain it dynamically through IServiceScopeFactory. Similarly, if a service necessitates a specific lifetime like "scoped," it should be registered with that lifetime and resolved appropriately. Understanding these lifetime management strategies prevents common errors associated with dependency injection.
IServiceScopeFactory. This factory allows the singleton processor to create a new scope and obtain a fresh DbContext whenever it needs one. Alternatively, the EventProcessor itself can be registered with a scoped lifetime. In this scenario, a singleton EventListener would useIServiceScopeFactoryto create a scope and resolve a scoped EventProcessor for each event it handles.Ultimately, the core principle is to avoid injecting scoped dependencies directly into singletons. If a singleton service requires access to a scoped service, it should obtain it dynamically throughIServiceScopeFactory. Similarly, if a service necessitates a specific lifetime like "scoped," it should be registered with that lifetime and resolved appropriately. Understanding these lifetime management strategies prevents common errors associated with dependency injection.