Pure DI Fundamentals
Dependency Injection encompassses three core dimensions: Object Composition, Lifetime Management, and Interception. This section explores implementation techniques across .NET frameworks without containers.
Application Composition Principles
Similar to culinary preparation where ingredients are prepped beforehand, application composition involves assembling components at integration points. The Composition Root connects independent modules during runtime initialization.
Object Composition Definition
Establishing component hierarchies within the Composition Root forms the foundation of Dependency Injection.
Console Application Composition
Console applications provide straightforward composition through the Main method:
class Program
{
static void Main(string[] args)
{
string dbConnection = GetDatabaseConfig();
CommandProcessor processor = BuildProcessor(dbConnection);
processor.Execute(args);
}
static CommandProcessor BuildProcessor(string connString)
{
IDataProvider provider = new DatabaseProvider(
new CommerceDb(connString));
return new CommandProcessor(provider);
}
}
Composition Roots should exclusively: load configurations, construct object graphs, invoke functionality, and manage disposables.
UWP Application Composition
Universal Windows Platform apps use MVVM patterns with navigation services:
public sealed partial class App : Application, INavigationHandler
{
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
this.NavigateTo<ProductListViewModel>();
}
private Page CreateView(Type viewModelType)
{
IProductSource source = new WebServiceCatalog();
if (viewModelType == typeof(ProductListViewModel))
{
return new ProductListPage(new ProductListViewModel(this, source));
}
// Additional view mappings
}
}
ViewModel initialization uses constructer injection:
public class ProductListViewModel : IViewModel
{
public ProductListViewModel(INavigationHandler nav, IProductSource source)
{
this.navigator = nav;
this.dataSource = source;
}
}
ASP.NET Core MVC Composition
Custom controller activators enable dependency injection:
public class MvcActivator : IControllerActivator
{
public object Create(ControllerContext ctx)
{
Type controllerType = ctx.ActionDescriptor.ControllerTypeInfo.AsType();
if (controllerType == typeof(CatalogController))
{
return new CatalogController(
new ProductService(new DatabaseRepository()));
}
// Additional controller mappings
}
}
Middleware components support dependency injection:
public class RequestLogger
{
private readonly ILogWriter logger;
public RequestLogger(ILogWriter logger) => this.logger = logger;
public async Task Process(HttpContext context, Func<Task> next)
{
logger.Write("Request initiated");
await next();
logger.Write("Request completed");
}
}
Key Principles
- Object Composition establishes component hierarchies within the Composition Root
- Composition Roots should isolate configuration loading from object construction
- UWP applications implement MVVM with ViewModels as injectable components
- ASP.NET Core uses IControllerActivator for controller dependency injection
- Middleware components can be constructed with dependencies via Composition Roots