Why it matters
the default DI container cannot resolve circular constructor graphs and will fail at runtime when the service is activated.
If two people each wait for the other to hand over the key first, the door never opens.
DI017
constructor-injection cycles such as `A -> B -> A`, including longer transitive loops. It follows effective registration precedence, including exact closed registrations before open-generic fallbacks, and mirrors the default container's constructor-set rule: the greediest resolvable constructor is analyzed only when its resolved service identifiers (type plus key) contain every other resolvable constructor's service identifiers. Equivalent reordered constructors therefore expose the same real cycle, while non-superset sets stay silent because activation is ambiguous.
Why it matters
the default DI container cannot resolve circular constructor graphs and will fail at runtime when the service is activated.
If two people each wait for the other to hand over the key first, the door never opens.
Install
dotnet add package DependencyInjection.Lifetime.Analyzers --version 2.18.24
README problem example
services.AddScoped<IOrderService, OrderService>();
services.AddScoped<IPaymentService, PaymentService>();
public sealed class OrderService : IOrderService
{
public OrderService(IPaymentService payment) { }
}
public sealed class PaymentService : IPaymentService
{
public PaymentService(IOrderService order) { }
}
README better pattern
Repo sample extraction
Sample app circular dependency
public class BadOrderService : IOrderService
{
public BadOrderService(IPaymentService payment) { }
}
Sample app safe pattern
public class GoodOrderService : IOrderService { }
Related guides
More documentation