The .NET built-in DI container registers services with three lifetimes — Transient (new per request), Scoped (new per HTTP request / scope), Singleton (one for app lifetime). .NET 8 added Keyed Services (IKeyedServiceProvider) for named service variants. Captive dependency bugs (Singleton capturing Scoped) are caught at startup. BackgroundServices must use IServiceScopeFactory, not inject Scoped services directly.
Each stage in order — click any step to read what it does.
Captive dependency rules: outer lifetimes cannot capture shorter-lived services.
The trade-offs worth knowing before you build this.
services.Configure<ServiceProviderOptions>(o => { o.ValidateScopes = true; o.ValidateOnBuild = true; }) catches captive dep bugs at startup.
Instead of injecting a factory that returns ICache by name, use keyed services and [FromKeyedServices]. Less code, fully DI managed.
Never inject Scoped services into Singleton BackgroundService constructors. Always create a scope per work unit with IServiceScopeFactory.
Sign in to share your feedback and join the discussion.