Ninject is dependency injector for .NET, practical realisation of pattern Dependency Injection (form of Inversion of Control pattern).
Suppose you have two classes DbRepository and Controller:
class Controller {
private DbRepository _repository;
// ... some methods that uses _repository
}
class DbRepository {
// ... some bussiness logic here ...
}
So, now you have two problems:
-
You must initialize
_repositoryto use it. You have several options for doing this:- Manually, within the constructor. But what if the constructor of DbRepository changes? You would need to rewrite your
Controllerclass because code it’s dependent upon was changed. It’s not hard if you have only oneController, but if you have a couple of classes that have a dependency on yourRepositoryyou have a real problem. -
You can use a service locator or factory. But now you have a dependency on your service locator. You have a global service locator and all code must use it. How you will you change the behavior of your service locator when you need to use it in one part of your code for activation logic but for something else in another part of your code? There is only one way – passing the service locator through constructors. But with more and more classes you will need to pass it more and more times. Anyway, it’s a good thought but in the long run, it’s a bad idea.
class Controller { private DbRepository _repository; public Controller() { _repository = GlobalServiceLocator.Get<DbRepository>() } // ... some methods that uses _repository } -
You can use dependency injection. Look at the code:
class Controller { private IRepository _repository; public Controller(IRepository repository) { _repository = repository; } }Now when you need your controller you write:
ninjectDevKernel.Get<Controller>();orninjectTestKernel.Get<Controller>();. You can switch beetween dependency resolvers as fast as you want. See? It’s simple, you don’t need to write a lot.
- Manually, within the constructor. But what if the constructor of DbRepository changes? You would need to rewrite your
-
You can’t create unit tests for it. Your
Controllerhas a dependency onDbRepositoryand if you want to test some method that uses repository, your code will go to the database and ask it for data. That’s slow, very slow. If your code inDbRepositorychanges, your unit test onControllerwill fall. Only integration test must warn you of ‘problems’ in this case. What you need in unit tests – is to isolate your classes and test only one class in one test (in ideal – only one method). If yourDbRepositorycode fails, you will think thatControllercode failed – and that’s bad (even if you have tests forDbRepositoryandController– they both will fail and you can start from the wrong place). It takes a lot of time to determine where the error really is. You need to know that class A is ok, and it was class B where something failed. -
When you want to replace
DbRepositorywith something else in all your classes, you have to do a lot of work. -
You can’t easily control the lifetime of
DbRepository. An object of this class is created on initialization ofControllerand deleted whenControlleris deleted. There is no sharing between different instances of theControllerclass and there is no sharing between other classes. With Ninject you can simply write:kernel.Bind<IRepository>().To<DbRepository>().InSingletonScope();
A special feature of dependency injection – agile development! You describe that your controller uses a repository with interface IRepository. You don’t need to write DbRepository, you can simply create a MemoryRepository class and develop Controller while another person develops DbRepository. When work on DbRepository is finished, you just rebind in your dependency resolver that default IRepository is now DbRepository. Have a lot of controllers? All of them will now use DbRepository. That’s cool.
Read more:
- Inversion of control (wiki)
- Dependency injection (wiki)
- Inversion of Control Containers and the Dependency Injection pattern (Martin Fowler)