What this prompt does
This prompt designs a dependency injection architecture for a [dotnet_version] application — typically a [project_type] with [service_count] services. It organizes registration into extension methods per [module_structure], explains Transient, Scoped, and Singleton lifetimes with examples from [lifetime_examples], implements a factory for [factory_scenario], uses .NET 8 keyed services for [keyed_scenario], applies the decorator pattern to [decorator_scenario], configures the options pattern for [config_sections], and adds startup validation that fails fast.
The structure works because the lifetime and validation steps map straight to real failures. Captive-dependency bugs and misused lifetimes — like a scoped DbContext injected into a singleton — are exactly the kind of thing that surfaces in production, so the prompt calls them out explicitly. Keyed services and the options pattern are what keep registration clean as the app grows, replacing hand-rolled factories and scattered configuration reads with patterns the framework supports directly.
When to use it
- You are wiring up a new .NET API and want DI organized per
[module_structure]from the start - You inherited an app with tangled registration and suspect lifetime misuse
- You hit a captive-dependency bug and need the lifetimes in
[lifetime_examples]straightened out - You need a factory or keyed services for runtime-selected implementations like
[keyed_scenario] - You want cross-cutting concerns added via the decorator pattern for
[decorator_scenario] - You want startup validation so missing or misconfigured services fail fast instead of at runtime
Example output
Expect an architecture walkthrough with code: per-module registration extension methods, lifetime explanations with concrete examples and common-mistake call-outs, factory implementation for runtime type selection, keyed-service registration compared against the factory approach, decorator-pattern setup via Scrutor or manual registration, options-pattern configuration showing IOptions, IOptionsSnapshot, and IOptionsMonitor, integration-test override examples, and fail-fast startup validation.
Pro tips
- Watch lifetimes carefully — the classic captive-dependency bug is a scoped service trapped inside a singleton, and naming your real
[lifetime_examples]helps the model flag it - Reach for keyed services in
[keyed_scenario]before hand-rolling a factory; selecting a notification sender by channel name is cleaner than a switch inside a factory class - Choose between
IOptions,IOptionsSnapshot, andIOptionsMonitorby reload needs — useIOptionsMonitorwhen config can change at runtime,IOptionswhen it can't - Use the decorator pattern for
[decorator_scenario]to add caching or logging without touching the original class, keeping cross-cutting concerns separate - Add the startup validation step so a missing registration fails at boot, not on the first request that needs it
- Keep registration in per-module extension methods so
[module_structure]stays readable as[service_count]grows - Register
HttpClientthrough the factory rather than as a raw singleton, since a long-lived client can hold stale DNS and exhaust sockets under load - Apply the decorator pattern via Scrutor for
[decorator_scenario]so caching and logging wrap the real implementation without the consuming code knowing or caring