Lesson 13 of 40 Architecture Advanced 45 min

Dependency Injection & Architecture Patterns

Design maintainable, testable applications using the built-in DI container, clean architecture, vertical slice architecture, and the mediator pattern.

Part 1: Service Lifetimes

LifetimeWhen to UseRegister
TransientLightweight, stateless servicesAddTransient
ScopedPer-request state (e.g., DbContext)AddScoped
SingletonShared app-wide state (e.g., cache)AddSingleton

Part 2: Keyed Services

// Register multiple implementations
builder.Services.AddKeyedSingleton<IPaymentGateway, StripeGateway>("stripe");
builder.Services.AddKeyedSingleton<IPaymentGateway, PayPalGateway>("paypal");

// Inject by key
public CheckoutService([FromKeyedServices("stripe")] IPaymentGateway gateway)

Part 3: MediatR & CQRS

Separate commands (write) from queries (read):
public record CreateOrderCommand(OrderDto Dto) : IRequest<Order>;

public class CreateOrderHandler : IRequestHandler<CreateOrderCommand, Order>
{
  public async Task<Order> Handle(CreateOrderCommand cmd, CancellationToken ct)
  {
    // Business logic here
  }
}

Part 4: Decorator Pattern via DI

// Add caching decorator without modifying original
builder.Services.AddScoped<IOrderRepository, OrderRepository>();
builder.Services.Decorate<IOrderRepository, CachedOrderRepository>();

// Scrutor NuGet package provides .Decorate()
Visual Studio 2026 Hands-On Projects Made Easy
Recommended Book

Visual Studio 2026 Hands-On Projects Made Easy

Build Real C# and .NET 10 Applications with Step-by-Step Screenshots, Databases, APIs, Testing, Deployment, and AI Tools