Cursor suggested a Scoped→Singleton DI bug. Here's how to catch it before merge.
You asked Cursor to add caching, retry, or background work to a .NET service. It returned compiling, test-passing code that ships a captured-dependency lifetime bug to production. This is the most expensive class of .NET DI mistake — and AI assistants make it constantly, because the patterns they learned from blog posts and Stack Overflow snippets almost never show DI registration. Here is the short answer, what's actually happening at runtime, and the 60-second rule that catches the bug at the constructor.
The short answer
A class registered as Singleton that takes a Scoped service in its constructor will capture that scoped instance for the lifetime of the application. Every request after the first one shares the same captured object — including any DbContext, repository, or unit-of-work it reaches through. The result is silent state corruption, not a clean exception.
The fix is to audit every constructor before merge: if the consumer is Singleton and any parameter is Scoped or Transient, refuse the suggestion or inject IServiceScopeFactory instead.
What's actually happening at runtime
IMemoryCache, ILogger<T>, hosted services, anything registered as AddSingleton is created once per process. DbContext, repositories, MediatR's ISender, anything registered as AddScoped is created once per HTTP request.
When the AI suggests adding caching to OrderService, it usually proposes injecting IMemoryCache and stashing entities directly. Those entities are still attached to a DbContext that's about to be disposed. The cache, alive for hours or days, holds graph references into disposed scoped infrastructure. The first request after a deploy looks fine. Request 50,000 explodes with ObjectDisposedException. Or — worse — silently corrupts a downstream record.
Why AI assistants ship this constantly
The patterns in AI training data — short tutorials, Stack Overflow answers, micro-snippets — almost always omit the DI registration block. A typical "caching with IMemoryCache" example is ten lines, with no mention of where the consumer is registered or with what lifetime. The model learned the surface pattern without the constraint that makes it safe. When you ask it to add caching to your codebase, it pattern-matches against the surface form and confidently ships the bug.
This is not a "the AI is dumb" critique. Most senior .NET engineers shipped this bug at least once before they learned to look for it. The patterns in the wild teach the wrong lesson — AI just industrialises that gap.
The fix in 60 seconds
Add a single .cursor/rules/dotnet-di.mdc rule that activates whenever Cursor edits a file containing AddSingleton, AddScoped, or a class constructor. The rule's job:
- When proposing a constructor parameter, look up the parameter type's registered lifetime in
Program.cs. - If the consumer is Singleton and the parameter is Scoped or Transient, refuse and surface the lifetime mismatch.
- If a
BackgroundServiceneeds scoped work, suggestIServiceScopeFactory+CreateScope()instead of direct injection. - If a long-lived cache is set up, ensure cached values are either projected DTOs or
AsNoTracking()'d.
The trick is scoping the rule to files where DI actually happens — not loading it on every prompt. Your token budget stays sane. The AI stays sharp on the file you're in.
Want the full picture?
The long-form essay walks the example end-to-end with code, covers the other four lifetime traps (HttpClient, hosted services, captured tracked entities, static helpers reaching scoped infrastructure), and shows the exact rule pattern.
→ Read: The Scoped→Singleton DI bug your AI just suggested (and how to catch it)
Try the boundary rule for free
The arch-core-lite.mdc rule is the boundary-guardian preview from the kit — a single drop-in Cursor rule that refuses cross-layer DI violations. No signup, no email.
Or get the full DI auditor (and the other three rules).
The complete Agentic Architect kit — 4 specialist rules including the full dotnet-di.mdc auditor + the persistence engine — is £19.99 one-time. Lifetime updates. MIT-licensed. 14-day refund.