Sometimes we can do some neat tricks with our DI Container, for example: auto-binding, managing singletons, managing one-instance-per-request etc. This is great, and can really simplify some scenarios.
The problem I have with this is that a particular class's concerns now get leaked to the application layer. If a class expects to be instantiated and managed in a particular way (e.g. as a singleton, or only once per http request), it is now up to the application layer to ensure that this occurs.
Some problems that occur:
1) Potential bugs, as the application could incorrectly setup the DI bindings.
2) It can be confusing when a developer wants to implement a package, as the rules for setting up the DI container are not provided by the package itself, and so instead must be documented in comments or accompanying test-cases (which is not ideal).
3) If the implementation of a class changes, it is now the responsibility of every application that uses the class to update their DI container bindings.
Here are some example bindings that you can do using NInject that all exhibit this problem:
public class MyApplicationsInjectionModule : NInjectModule
{
public void Load()
{
Bind<IFoo>().ToConstant(FooThatShouldBeASingleton.Instant);
Bind<IFoo>().To<FooThatShouldBeASingleton>().AsSingleton();
Bind<IFoo>().To<FooThatShouldOnlyBeInstantiatedOncePerRequest>().InRequestScope();
}
}
My experience is only with NInject - perhaps some other DI containers deal with this problem more elegantly.
What strategies can we take to avoid these problems, without giving up the power that a DI container provides?