Phase 18 of 30 · Topic 18.2

The Captive Dependency Pitfall & Scope Validation

1Concept

A Captive Dependency occurs when a Singleton service injects a Scoped service. The Scoped service is captured by the Singleton and never disposed, causing memory leaks and database connection pool exhaustion.

2Architecture Diagram

[ Singleton CacheService ]
           │ (Captures and holds forever!)
           ▼
[ Scoped DbContext ] ──> NEVER Disposed! Concurrency collisions on subsequent HTTP requests!

3Code Example

C# 13 & .NET 9
using System;
using Microsoft.Extensions.DependencyInjection;

public class CaptiveDependencyDetection
{
    public static void Main()
    {
        var services = new ServiceCollection();
        
        // Enabling ValidateScopes:
        var provider = services.BuildServiceProvider(new ServiceProviderOptions
        {
            ValidateScopes = true,
            ValidateOnBuild = true
        });

        Console.WriteLine("ValidateScopes: true guarantees runtime exceptions if a Singleton captures a Scoped service.");
    }
}

4Expected Output

ValidateScopes: true guarantees runtime exceptions if a Singleton captures a Scoped service.

5Key Takeaways

  • Always enable `ValidateScopes = true` in development environments.
  • If a Singleton requires a Scoped service, inject `IServiceScopeFactory` and create explicit transient scopes.
  • Never store Scoped service instances in static or singleton fields.