Dependency Injection Advanced
Master advanced DI patterns for flexible, testable code.
By EMEPublished: February 20, 2025
dependency injectioniocaspnet coredesign patterns
A Simple Analogy
Advanced DI is like a smart HR department. Instead of employees bringing their own tools, HR provides exactly what each person needs, when they need it, from a central warehouse.
Why Advanced DI?
- Flexible composition: Change implementations without code changes
- Testability: Inject mocks for unit tests
- Decoupling: Components don't depend on implementations
- Lifecycle control: Manage object lifetimes precisely
- Factory patterns: Complex object creation
Service Lifetimes
// Transient: New instance every time
services.AddTransient<IUnitOfWork, UnitOfWork>();
// Good for: Stateless services, repositories
// Scoped: One per request (default in web)
services.AddScoped<IOrderService, OrderService>();
// Good for: DbContext, services managing state
// Singleton: One instance forever
services.AddSingleton<ICache, MemoryCache>();
// Good for: Caches, configuration, logging
builder.Services.AddScoped<IOrderService>(provider =>
{
var db = provider.GetRequiredService<DbContext>();
var logger = provider.GetRequiredService<ILogger<OrderService>>();
return new OrderService(db, logger);
});
Factory Patterns
// Factory delegate
services.AddScoped<IOrderService>(provider =>
{
var environment = provider.GetRequiredService<IHostEnvironment>();
return environment.IsProduction()
? new ProductionOrderService()
: new DevelopmentOrderService();
});
// Keyed services (named services)
services.AddScoped<IRepository>("orders", _ => new OrderRepository());
services.AddScoped<IRepository>("users", _ => new UserRepository());
var orderRepo = provider.GetKeyedService<IRepository>("orders");
// Generic factory
public class ServiceFactory<T> where T : class
{
public T Create(IServiceProvider provider)
{
// Complex creation logic
return ActivatorUtilities.CreateInstance<T>(provider);
}
}
Decorator Pattern
// Original service
public interface IOrderService
{
Task<Order> GetAsync(int id);
}
public class OrderService : IOrderService
{
public async Task<Order> GetAsync(int id) => await db.Orders.FindAsync(id);
}
// Decorator adds caching
public class CachedOrderService : IOrderService
{
private readonly IOrderService _inner;
private readonly ICache _cache;
public async Task<Order> GetAsync(int id)
{
var key = $"order-{id}";
var cached = _cache.Get<Order>(key);
if (cached != null) return cached;
var order = await _inner.GetAsync(id);
_cache.Set(key, order, TimeSpan.FromHours(1));
return order;
}
}
// Register
services.AddScoped<OrderService>();
services.AddScoped<IOrderService>(provider =>
new CachedOrderService(provider.GetRequiredService<OrderService>(), cache));
OpenGenericServices
// Register handler for all types
services.AddTransient(typeof(IHandler<>), typeof(Handler<>));
// Usage
public interface IHandler<T>
{
Task HandleAsync(T item);
}
public class Handler<T> : IHandler<T>
{
public async Task HandleAsync(T item) { }
}
// Automatically resolves Handler<Order>, Handler<User>, etc.
var orderHandler = provider.GetRequiredService<IHandler<Order>>();
Module Pattern
public class RepositoryModule : ServiceCollectionExtension
{
public static IServiceCollection AddRepositories(
this IServiceCollection services)
{
services.AddScoped<IOrderRepository, OrderRepository>();
services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<IProductRepository, ProductRepository>();
return services;
}
}
// Usage
builder.Services.AddRepositories();
Best Practices
- Register abstractions: Always use interfaces
- Manage lifetimes: Choose appropriate scope
- Use factories: For complex object creation
- Avoid service locator: Always inject dependencies
- Consider decorators: Add cross-cutting concerns
Related Concepts
- Castle Windsor container
- Autofac container
- Service locator pattern (avoid)
- Property injection
Summary
Advanced DI enables flexible, testable architectures. Master factory patterns, decorators, and keyed services to build maintainable, loosely-coupled applications.