← ClaudeAtlas

dependency-injection-lifetimeslisted

Review .NET dependency injection registrations for captive dependencies, scoped-in-singleton bugs, IServiceProvider abuse, disposal issues, and HttpClient registration. Use when writing or reviewing DI container registrations or constructor injection.
Sarmkadan/dotnet-senior-skills · ★ 0 · AI & Automation · score 72
Install: claude install-skill Sarmkadan/dotnet-senior-skills
# Dependency Injection Lifetimes ## The one rule that causes 90% of DI bugs A service must not depend on anything with a SHORTER lifetime. Singleton -> Scoped is the captive dependency: the singleton captures the first scope's instance forever. ```csharp // WRONG: singleton captures a scoped DbContext services.AddSingleton<ICacheWarmer, CacheWarmer>(); // ctor takes AppDbContext ``` Symptoms in production: `ObjectDisposedException: Cannot access a disposed context`, cross-request data bleed, "second request returns stale data". The default container validates this only when `ValidateScopes` is on - which is Development-only by default. Turn it on everywhere; the check is cheap: ```csharp builder.Host.UseDefaultServiceProvider(o => { o.ValidateScopes = true; o.ValidateOnBuild = true; }); ``` `ValidateOnBuild` also catches missing registrations at startup instead of first-request. ## Consuming scoped services from singletons (the right way) Background services and singletons that need scoped services create a scope per unit of work: ```csharp public class OutboxProcessor(IServiceScopeFactory scopeFactory) : BackgroundService { protected override async Task ExecuteAsync(CancellationToken ct) { while (!ct.IsCancellationRequested) { await using var scope = scopeFactory.CreateAsyncScope(); var db = scope.ServiceProvider.GetRequiredService<AppDbContext>(); // one batch = one scope = one DbContext } } }