Dependency Injection & Architecture Patterns
In this lesson, you will learn how dependency injection supports maintainable design and how architecture patterns help you organize applications that are easier to test, extend, and understand.
← Back to Visual Studio 2026 Tutorial HomeWhat you will learn
- How service lifetimes work in the built-in container
- How keyed services support multiple implementations
- How mediator-style patterns support separation of concerns
- How decorators extend behavior without changing core services
- How to think about architecture choices more clearly
Part 1: Service lifetimes
When you register a service in the dependency injection container, you choose how long that service should live. The right lifetime depends on what the service does and how it is used.
| Lifetime | When to use | Registration |
|---|---|---|
| Transient | Lightweight, stateless services | AddTransient |
| Scoped | Per-request state, such as DbContext | AddScoped |
| Singleton | Shared app-wide services, such as caches | AddSingleton |
Part 2: Keyed services
Sometimes you need more than one implementation of the same interface. Keyed services let you register multiple implementations and select the one you need more explicitly.
This is useful when different providers or strategies share the same contract but behave differently.
Part 3: MediatR and CQRS ideas
A mediator-based approach can help separate requests from the code that handles them. This often fits well with CQRS, where reads and writes are treated as different kinds of operations.
This pattern can improve organization in larger applications, especially when use cases become more complex.
Part 4: Decorator pattern with dependency injection
A decorator adds behavior around an existing service without changing the original implementation. This is useful for concerns such as caching, logging, retries, or metrics.
This helps you keep responsibilities separate and avoids overloading one class with too many duties.
When to use common architecture ideas
| Approach | Best used for |
|---|---|
| Dependency Injection | Reducing coupling and improving configurability |
| Scoped lifetimes | Request-based services such as data access |
| Keyed services | Selecting between multiple implementations |
| Mediator pattern | Separating request handling from controllers or UI logic |
| Decorator pattern | Adding cross-cutting behavior without changing core classes |
A practical architecture workflow
Best practices
- Do not add patterns just to make the code look advanced
- Choose service lifetimes carefully
- Prefer clear design over unnecessary abstraction
- Keep business logic separated from infrastructure details
- Use decorators for cross-cutting concerns when appropriate
- Refactor architecture gradually as the application grows
Summary
In this lesson, you learned how dependency injection lifetimes work, how keyed services support multiple implementations, and how architectural patterns such as mediator-style handling and decorators can improve application structure.
In the next lesson, you will continue with real-time application patterns.