For product development of any reasonably sized application that practice loose coupling and follows the SOLID principles, .NET Core’s DI container (MS.DI) is unsuited, because:
- It doesn’t help you in verifying your configuration, making it really hard to diagnose problems that come from common misconfigurations. In a reasonably sized application, it’s actually quite hard to spot these mistakes yourself.
UPDATE: Version 3 of MS.DI now contains a feature calledValidateOnBuild
, but the only thing it does is check whether all dependencies of all registrations can be satisfied. - It is impossible to apply Cross-Cutting Concerns using interceptors or decorators in a maintainable fashion. This makes maintaining any reasonably sized application more expensive.
UPDATE: There are several third-party libraries that try to fill the gap, but due to limitations in MS.DI, they can’t completely fill that gap (e.g. decorate open-generic registrations, ensure disposal of decorated instances, etc.) - Although MS.DI supports mapping of open-generic abstractions to open-generic implementations, its implementation is rather naive and is unable to work with generic types with type constraints, more complex generic type mappings, and variance.
- It is impossible to make conditional/contextual registrations, in such way that registrations only get injected to a certain set of consumers, while using Auto-Wiring. e.g. when having two components
Service1
andService2
that both depend onILogger
, you might want to injectService1
withNullLogger
andService2
withFileLogger
, or you wantService1
to be injected withLogger<Service1>
andService2
withLogger<Service2>
.
The main reason for those limitations to exist is because it’s the goal of the built-in container to provide DI capabilities to especially the framework itself, while keeping its feature set to a minimum in the hope that more-mature DI containers would be able to integrate with it. In other words, it tries to act as an Least-Common Denominator (LCD). Because of its LCD function, it can never grow to a full-fledged DI Container that is practical for application development (not without breaking the promise of being an LCD).
If you start with a new and simple project, my advice is to apply Pure DI. This means you hand-wire components inside the Composition Root without using a container and without creating your own DI Container. Instead you resolve your types by plugging in your custom IControllerActivator. Later on, when features such as Auto-Wiring, Auto-Registration and Interception would improve maintainability of your Composition Root, switch to one of the established DI libraries that fits your requirements.