安装
npx skills add https://github.com/aaronontheweb/dotnet-skills --skill dependency-injection-patterns
- Dependency Injection Patterns
- When to Use This Skill
- Use this skill when:
- Organizing service registrations in ASP.NET Core applications
- Avoiding massive Program.cs/Startup.cs files with hundreds of registrations
- Making service configuration reusable between production and tests
- Designing libraries that integrate with Microsoft.Extensions.DependencyInjection
- Reference Files
- advanced-patterns.md
-
- Testing with DI extensions, Akka.NET actor scope management, conditional/factory/keyed registration patterns
- The Problem
- Without organization, Program.cs becomes unmanageable:
- // BAD: 200+ lines of unorganized registrations
- var
- builder
- =
- WebApplication
- .
- CreateBuilder
- (
- args
- )
- ;
- builder
- .
- Services
- .
- AddScoped
- <
- IUserRepository
- ,
- UserRepository
- >
- (
- )
- ;
- builder
- .
- Services
- .
- AddScoped
- <
- IOrderRepository
- ,
- OrderRepository
- >
- (
- )
- ;
- builder
- .
- Services
- .
- AddScoped
- <
- IProductRepository
- ,
- ProductRepository
- >
- (
- )
- ;
- builder
- .
- Services
- .
- AddScoped
- <
- IUserService
- ,
- UserService
- >
- (
- )
- ;
- // ... 150 more lines ...
- Problems: hard to find related registrations, no clear boundaries, can't reuse in tests, merge conflicts.
- The Solution: Extension Method Composition
- Group related registrations into extension methods:
- // GOOD: Clean, composable Program.cs
- var
- builder
- =
- WebApplication
- .
- CreateBuilder
- (
- args
- )
- ;
- builder
- .
- Services
- .
- AddUserServices
- (
- )
- .
- AddOrderServices
- (
- )
- .
- AddEmailServices
- (
- )
- .
- AddPaymentServices
- (
- )
- .
- AddValidators
- (
- )
- ;
- var
- app
- =
- builder
- .
- Build
- (
- )
- ;
- Extension Method Pattern
- Basic Structure
- namespace
- MyApp
- .
- Users
- ;
- public
- static
- class
- UserServiceCollectionExtensions
- {
- public
- static
- IServiceCollection
- AddUserServices
- (
- this
- IServiceCollection
- services
- )
- {
- services
- .
- AddScoped
- <
- IUserRepository
- ,
- UserRepository
- >
- (
- )
- ;
- services
- .
- AddScoped
- <
- IUserReadStore
- ,
- UserReadStore
- >
- (
- )
- ;
- services
- .
- AddScoped
- <
- IUserWriteStore
- ,
- UserWriteStore
- >
- (
- )
- ;
- services
- .
- AddScoped
- <
- IUserService
- ,
- UserService
- >
- (
- )
- ;
- services
- .
- AddScoped
- <
- IUserValidationService
- ,
- UserValidationService
- >
- (
- )
- ;
- return
- services
- ;
- }
- }
- With Configuration
- namespace
- MyApp
- .
- Email
- ;
- public
- static
- class
- EmailServiceCollectionExtensions
- {
- public
- static
- IServiceCollection
- AddEmailServices
- (
- this
- IServiceCollection
- services
- ,
- string
- configSectionName
- =
- "EmailSettings"
- )
- {
- services
- .
- AddOptions
- <
- EmailOptions
- >
- (
- )
- .
- BindConfiguration
- (
- configSectionName
- )
- .
- ValidateDataAnnotations
- (
- )
- .
- ValidateOnStart
- (
- )
- ;
- services
- .
- AddSingleton
- <
- IMjmlTemplateRenderer
- ,
- MjmlTemplateRenderer
- >
- (
- )
- ;
- services
- .
- AddSingleton
- <
- IEmailLinkGenerator
- ,
- EmailLinkGenerator
- >
- (
- )
- ;
- services
- .
- AddScoped
- <
- IUserEmailComposer
- ,
- UserEmailComposer
- >
- (
- )
- ;
- services
- .
- AddScoped
- <
- IEmailSender
- ,
- SmtpEmailSender
- >
- (
- )
- ;
- return
- services
- ;
- }
- }
- File Organization
- Place extension methods near the services they register:
- src/
- MyApp.Api/
- Program.cs # Composes all Add* methods
- MyApp.Users/
- Services/
- UserService.cs
- UserServiceCollectionExtensions.cs # AddUserServices()
- MyApp.Orders/
- OrderServiceCollectionExtensions.cs # AddOrderServices()
- MyApp.Email/
- EmailServiceCollectionExtensions.cs # AddEmailServices()
- Convention
- :
- {Feature}ServiceCollectionExtensions.cs
- next to the feature's services.
- Naming Conventions
- Pattern
- Use For
- Add{Feature}Services()
- General feature registration
- Add{Feature}()
- Short form when unambiguous
- Configure{Feature}()
- When primarily setting options
- Use{Feature}()
- Middleware (on IApplicationBuilder)
- Testing Benefits
- The
- Add*
- pattern lets you
- reuse production configuration in tests
- and only override what's different. Works with WebApplicationFactory, Akka.Hosting.TestKit, and standalone ServiceCollection.
- See
- advanced-patterns.md
- for complete testing examples.
- Layered Extensions
- For larger applications, compose extensions hierarchically:
- public
- static
- class
- AppServiceCollectionExtensions
- {
- public
- static
- IServiceCollection
- AddAppServices
- (
- this
- IServiceCollection
- services
- )
- {
- return
- services
- .
- AddDomainServices
- (
- )
- .
- AddInfrastructureServices
- (
- )
- .
- AddApiServices
- (
- )
- ;
- }
- }
- public
- static
- class
- DomainServiceCollectionExtensions
- {
- public
- static
- IServiceCollection
- AddDomainServices
- (
- this
- IServiceCollection
- services
- )
- {
- return
- services
- .
- AddUserServices
- (
- )
- .
- AddOrderServices
- (
- )
- .
- AddProductServices
- (
- )
- ;
- }
- }
- Akka.Hosting Integration
- The same pattern works for Akka.NET actor configuration:
- public
- static
- class
- OrderActorExtensions
- {
- public
- static
- AkkaConfigurationBuilder
- AddOrderActors
- (
- this
- AkkaConfigurationBuilder
- builder
- )
- {
- return
- builder
- .
- WithActors
- (
- (
- system
- ,
- registry
- ,
- resolver
- )
- =>
- {
- var
- orderProps
- =
- resolver
- .
- Props
- <
- OrderActor
- >
- (
- )
- ;
- var
- orderRef
- =
- system
- .
- ActorOf
- (
- orderProps
- ,
- "orders"
- )
- ;
- registry
- .
- Register
- <
- OrderActor
- >
- (
- orderRef
- )
- ;
- }
- )
- ;
- }
- }
- // Usage in Program.cs
- builder
- .
- Services
- .
- AddAkka
- (
- "MySystem"
- ,
- (
- builder
- ,
- sp
- )
- =>
- {
- builder
- .
- AddOrderActors
- (
- )
- .
- AddInventoryActors
- (
- )
- .
- AddNotificationActors
- (
- )
- ;
- }
- )
- ;
- See
- akka-hosting-actor-patterns
- skill for complete Akka.Hosting patterns.
- Anti-Patterns
- Don't: Register Everything in Program.cs
- // BAD: Massive Program.cs with 200+ lines of registrations
- Don't: Create Overly Generic Extensions
- // BAD: Too vague, doesn't communicate what's registered
- public
- static
- IServiceCollection
- AddServices
- (
- this
- IServiceCollection
- services
- )
- {
- ..
- .
- }
- Don't: Hide Important Configuration
- // BAD: Buried settings
- public
- static
- IServiceCollection
- AddDatabase
- (
- this
- IServiceCollection
- services
- )
- {
- services
- .
- AddDbContext
- <
- AppDbContext
- >
- (
- options
- =>
- options
- .
- UseSqlServer
- (
- "hardcoded-connection-string"
- )
- )
- ;
- // Hidden!
- }
- // GOOD: Accept configuration explicitly
- public
- static
- IServiceCollection
- AddDatabase
- (
- this
- IServiceCollection
- services
- ,
- string
- connectionString
- )
- {
- services
- .
- AddDbContext
- <
- AppDbContext
- >
- (
- options
- =>
- options
- .
- UseSqlServer
- (
- connectionString
- )
- )
- ;
- }
- Best Practices Summary
- Practice
- Benefit
- Group related services into
- Add*
- methods
- Clean Program.cs, clear boundaries
- Place extensions near the services they register
- Easy to find and maintain
- Return
- IServiceCollection
- for chaining
- Fluent API
- Accept configuration parameters
- Flexibility
- Use consistent naming (
- Add{Feature}Services
- )
- Discoverability
- Test by reusing production extensions
- Confidence, less duplication
- Lifetime Management
- Lifetime
- Use When
- Examples
- Singleton
- Stateless, thread-safe, expensive to create
- Configuration, HttpClient factories, caches
- Scoped
- Stateful per-request, database contexts
- DbContext, repositories, user context
- Transient
- Lightweight, stateful, cheap to create
- Validators, short-lived helpers
- // SINGLETON: Stateless services, shared safely
- services
- .
- AddSingleton
- <
- IMjmlTemplateRenderer
- ,
- MjmlTemplateRenderer
- >
- (
- )
- ;
- // SCOPED: Database access, per-request state
- services
- .
- AddScoped
- <
- IUserRepository
- ,
- UserRepository
- >
- (
- )
- ;
- // TRANSIENT: Cheap, short-lived
- services
- .
- AddTransient
- <
- CreateUserRequestValidator
- >
- (
- )
- ;
- Scoped services require a scope.
- ASP.NET Core creates one per HTTP request. In background services and actors, create scopes manually.
- See
- advanced-patterns.md
- for actor scope management patterns.
- Common Mistakes
- Injecting Scoped into Singleton
- // BAD: Singleton captures scoped service - stale DbContext!
- public
- class
- CacheService
- // Registered as Singleton
- {
- private
- readonly
- IUserRepository
- _repo
- ;
- // Scoped - captured at startup!
- }
- // GOOD: Inject IServiceProvider, create scope per operation
- public
- class
- CacheService
- {
- private
- readonly
- IServiceProvider
- _serviceProvider
- ;
- public
- async
- Task
- <
- User
- >
- GetUserAsync
- (
- string
- id
- )
- {
- using
- var
- scope
- =
- _serviceProvider
- .
- CreateScope
- (
- )
- ;
- var
- repo
- =
- scope
- .
- ServiceProvider
- .
- GetRequiredService
- <
- IUserRepository
- >
- (
- )
- ;
- return
- await
- repo
- .
- GetByIdAsync
- (
- id
- )
- ;
- }
- }
- No Scope in Background Work
- // BAD: No scope for scoped services
- public
- class
- BadBackgroundService
- :
- BackgroundService
- {
- private
- readonly
- IOrderService
- _orderService
- ;
- // Scoped - will throw!
- }
- // GOOD: Create scope for each unit of work
- public
- class
- GoodBackgroundService
- :
- BackgroundService
- {
- private
- readonly
- IServiceScopeFactory
- _scopeFactory
- ;
- protected
- override
- async
- Task
- ExecuteAsync
- (
- CancellationToken
- ct
- )
- {
- using
- var
- scope
- =
- _scopeFactory
- .
- CreateScope
- (
- )
- ;
- var
- orderService
- =
- scope
- .
- ServiceProvider
- .
- GetRequiredService
- <
- IOrderService
- >
- (
- )
- ;
- // ...
- }
- }
- Resources
- Microsoft.Extensions.DependencyInjection
- :
- https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection
- Akka.Hosting
- :
- https://github.com/akkadotnet/Akka.Hosting
- Akka.DependencyInjection
- :
- https://getakka.net/articles/actors/dependency-injection.html
- Options Pattern
- See
microsoft-extensions-configuration
skill
← 返回排行榜