Skip to main content

configuring-dotnet-dependency-injection

Register and review .NET dependency-injection services and lifetimes on IServiceCollection. USE FOR: adding a registration, choosing singleton/scoped/transient, grouping registrations behind a feature extension, assembly scanning with Scrutor, or validating a service graph. DO NOT USE FOR: choosing which kind of type to declare (use designing-dotnet-types), or configuring the host builder and its lifecycle (use configuring-dotnet-hosting).

소스 정보

저장소
Nice3point/revit-skills
최근 소스 활동
2026년 10월 7일 21:21
감지된 SKILL.md 언어
영어
스타
16
포크
3

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
configuring-dotnet-dependency-injection
description
Register and review .NET dependency-injection services and lifetimes on IServiceCollection. USE FOR: adding a registration, choosing singleton/scoped/transient, grouping registrations behind a feature extension, assembly scanning with Scrutor, or validating a service graph. DO NOT USE FOR: choosing which kind of type to declare (use designing-dotnet-types), or configuring the host builder and its lifecycle (use configuring-dotnet-hosting).
license
MIT
# Configuring .NET Dependency Injection Register a service in the composition that manages its lifetime, grouped with the capability it belongs to. ## When to use - Adding or reviewing an `IServiceCollection` registration. - Choosing a lifetime, or debugging a captive-dependency or disposal problem. - Scanning an assembly for conventional registrations. ## Workflow ### Step 1: Register with the owning capability Group the registration in a feature extension method that returns `IServiceCollection` for fluent chaining; do not scatter `AddX` calls across the composition root. ```csharp public static class EmailServiceCollectionExtensions { extension(IServiceCollection services) { public IServiceCollection AddEmailSenders() { services.AddSingleton<IEmailSender, SmtpEmailSender>(); return services; } } } ``` ### Step 2: Choose the lifetime from state and concurrency - **Singleton** — thread-safe, process-wide state, or a resource owned for the process lifetime. - **Scoped** — one instance per operation; the host opens a scope per window, request, or endpoint. - **Transient** — lightweight, stateless, constructed per consumer. Never inject a scoped service into a singleton, and never make a service singleton when it stores per-operation mutable state. ### Step 3: Register an interface only for a real boundary Register the concrete type when no consumer needs an abstraction; register `interface + implementation` when a consumer depends on an intentional seam. Register a hosted service separately from its ordinary contract when both resolve to the same process-owned instance. ### Step 4: Scan when registrations are conventional Use Scrutor's `Scan` to register many types by convention, not by listing each, when they share a marker interface or naming pattern. ```csharp services.Scan(scan => scan .FromAssemblyOf<SmtpEmailSender>() .AddClasses(classes => classes.AssignableTo<IValidator>()) .AsImplementedInterfaces() .WithTransientLifetime()); ``` ### Step 5: Create an extension for group registration Move every registration group — a set of related `AddX` calls or a Scrutor `Scan` — into its capability's extension method, and let the host composition root call only those methods. The host configuration contains no registration detail. Declare the extension with a C# 14 extension block; the `IServiceCollection` receiver is named once for the whole capability: ```csharp public static class EmailServiceCollectionExtensions { extension(IServiceCollection services) { public IServiceCollection AddEmailSenders() { services.AddSingleton<IEmailTemplateStore, FileEmailTemplateStore>(); services.Scan(scan => scan .FromAssemblyOf<SmtpEmailSender>() .AddClasses(classes => classes.AssignableTo<IEmailSender>()) .AsImplementedInterfaces() .WithSingletonLifetime()); return services; } } } ``` The composition root then reads as a flat list of capabilities, with no `AddX` or `Scan` detail inlined: ```csharp services.AddEmailSenders(); ``` ### Step 6: Verify the graph Build the host through its normal entry point and resolve the changed service through the owning path or a focused composition test. Never construct a second `ServiceProvider` in production registration code. ## Validation - [ ] The host that provides the behavior contains the registration. - [ ] The lifetime matches state, concurrency, and disposal needs. - [ ] No singleton captures a scoped or transient dependency. - [ ] Registrations are grouped with their capability, and the normal host composition succeeds. - [ ] The composition root calls only capability extension methods; no `AddX` group or Scrutor `Scan` is inlined where the host is configured. ## Common Pitfalls | Pitfall | Correct approach | |---------------------------------------------------------------------|-----------------------------------------------------------------------------------------| | Scoped service injected into a singleton | Make the consumer scoped, or pass a factory / `IServiceScopeFactory`. | | Singleton storing per-request mutable state | Use scoped or transient. | | `Scan` not found | The `Scrutor` package is not referenced in the project. | | A second `new ServiceProvider()` to resolve something | Resolve through the real host or a composition test. | | `AddX` group or Scrutor `Scan` inlined where the host is configured | Wrap it in a capability extension, for example `AddEmailSenders`, and call it from the root. |
GitHub에서 보기