DI009

Open Generic Captive Dependency

Open generic singleton registrations that depend on shorter-lived services, including common registration-shape variants such as TryAddSingleton(...), ServiceDescriptor.Singleton(...), keyed open-generic singleton registrations, and IEnumerable<T> constructor captures where the element service is shorter-lived.

Warning Default severity · Code fix: Yes

Why it matters

Every closed generic instance inherits the lifetime mismatch.

If the recipe is wrong at the top of the cookbook, every dish made from it comes out wrong.

README problem example

services.AddScoped<IScopedService, ScopedService>();
services.AddSingleton(typeof(IRepository<>), typeof(Repository<>));

public sealed class Repository<T> : IRepository<T>
{
    public Repository(IScopedService scoped) { }
}

README better pattern

services.AddScoped(typeof(IRepository<>), typeof(Repository<>));

Yes. Can adjust lifetime for open generic registrations.

Repo sample extraction

Examples pulled from the sample app

Open full sample file

Sample app warning case

public class BadRepository<T> : IBadRepository<T>
{
    private readonly IScopedService _scopedService;

    // DI009 will be reported on the registration line for this constructor
    public BadRepository(IScopedService scopedService)
    {
        _scopedService = scopedService;
    }

    public T? Get(int id)
    {
#pragma warning disable DI007 // Intentional use of service locator in sample
        _scopedService.DoWork();
#pragma warning restore DI007
        return default;
    }

    public void Save(T entity)
    {
#pragma warning disable DI007 // Intentional use of service locator in sample
        _scopedService.DoWork();
#pragma warning restore DI007
    }
}

Sample app safe pattern

public class GoodScopedRepository<T> : IGoodScopedRepository<T>
{
    private readonly IScopedService _scopedService;

    public GoodScopedRepository(IScopedService scopedService)
    {
        _scopedService = scopedService;
    }

    public T? Get(int id)
    {
#pragma warning disable DI007 // Intentional use of service locator in sample
        _scopedService.DoWork();
#pragma warning restore DI007
        return default;
    }
}

Nearby diagnostics

Other rules in this family

All 37 rules