What is Ninject and when do you use it?

I have been helping a few friends on a project and there is a class that uses Ninject. I am fairly new to C# and I have no idea what that class is doing, which is why I need to understand Ninject. Can anyone explain what Ninject is and when does one use it(with example if possible)? Or if you can point to some links that would be great too.

I tried this question: Ninject tutorials/documentations? but it didn't really help a beginner like me.


Solution 1:

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:

  1. You must initialize _repository to use it. You have several options for doing this:

    1. Manually, within the constructor. But what if the constructor of DbRepository changes? You would need to rewrite your Controller class because code it's dependent upon was changed. It's not hard if you have only one Controller, but if you have a couple of classes that have a dependency on your Repository you have a real problem.
    2. 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
      }
      
    3. 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>(); or ninjectTestKernel.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.

  2. You can't create unit tests for it. Your Controller has a dependency on DbRepository and 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 in DbRepository changes, your unit test on Controller will 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 your DbRepository code fails, you will think that Controller code failed - and that's bad (even if you have tests for DbRepository and Controller - 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.

  3. When you want to replace DbRepository with something else in all your classes, you have to do a lot of work.

  4. You can't easily control the lifetime of DbRepository. An object of this class is created on initialization of Controller and deleted when Controller is deleted. There is no sharing between different instances of the Controller class 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:

  1. Inversion of control (wiki)
  2. Dependency injection (wiki)
  3. Inversion of Control Containers and the Dependency Injection pattern (Martin Fowler)

Solution 2:

Ninject is an Inversion of Control container.

What does it do?

Suppose you have a Car class that depends on a Driver class.

public class Car 
{
   public Car(IDriver driver)
   {
      ///
   }
}

In order to use the Car class you build it like so:

IDriver driver = new Driver();
var car = new Car(driver);

A IoC containter centralizes the knowledge about how to build classes. It is a central repository that knows a few things. For example, it knows that the concrete class that you need to use to build a car is a Driver and not any other IDriver.

For example, if you are developing a MVC application, you can tell Ninject how to build your controllers. You do so by registering which concrete classes satisfy specific interfaces. At run time Ninject will figure out which classes are needed to build the required controller, and all behind the scenes.

// Syntax for binding
Bind<IDriver>().To<Driver>();

This is beneficial because it lets you build systems that are more easily unit testable. Suppose that Driver encapsulates all database access for Car. In a unit test for Car you can do this:

IDriver driver = new TestDriver(); // a fake driver that does not go to the db
var car = new Car(driver);

There are entire frameworks that take care of automatically creating testing classes for you and they are called mocking frameworks.

For more information:

  • GitHub/Ninject Home
  • Inversion of Control
  • Inversion of Control Containers and the Dependency Injection pattern
  • Mock Object

Solution 3:

Other answers are great but I would also like to point out this Implementing Dependency Injection using Ninject article.
This is one of the best articles I ever read which explains Dependency Injection and Ninject with a very elegant example.

Here's the snippet from the article:

Below Interface will be implemented by our (SMSService) and (MockSMSService), basically the new Interface (ISMSService) will expose the same behaviors of both services as the code below:

public interface ISMSService
 {
 void SendSMS(string phoneNumber, string body);
 }

(SMSService) implementation to implement the (ISMSService) interface:

public class SMSService : ISMSService
 {
 public void SendSMS(string mobileNumber, string body)
 {
 SendSMSUsingGateway(mobileNumber, body);
 }




private void SendSMSUsingGateway(string mobileNumber, string body)
 {
 /*implementation for sending SMS using gateway*/
Console.WriteLine("Sending SMS using gateway to mobile: 
    {0}. SMS body: {1}", mobileNumber, body);
 }
 }

(MockSMSService) with totally different implementation using the same interface:

public class MockSMSService :ISMSService
 {
 public void SendSMS(string phoneNumber, string body)
 {
 SaveSMSToFile(phoneNumber,body);
 }

private void SaveSMSToFile(string mobileNumber, string body)
 {
 /*implementation for saving SMS to a file*/
Console.WriteLine("Mocking SMS using file to mobile: 
    {0}. SMS body: {1}", mobileNumber, body);
 }
 }

we need to implement a change to our (UIHandler) class constructor to pass the dependency through it, by doing this, the code which uses the (UIHandler) can determine which concrete implementation of (ISMSService) to use:

public class UIHandler
 {
 private readonly ISMSService _SMSService;

public UIHandler(ISMSService SMSService)
 {
 _SMSService = SMSService;
 }
 public void SendConfirmationMsg(string mobileNumber) {

 _SMSService.SendSMS(mobileNumber, "Your order has been shipped successfully!");
 }
 }

Now, we have to create a separate class (NinjectBindings) which inherits from (NinjectModule). This class will be responsible to resolve dependencies at run time, then we’ll override the load event which is used to configure the binding in it. The nice thing about Ninject is that we do not need to change our code in (ISMSService), (SMSService), and (MockSMSService).

public class NinjectBindings : Ninject.Modules.NinjectModule
 {
 public override void Load()
 {
 Bind<ISMSService>().To<MockSMSService>();
 }
 }

Now in UI form code, we’ll use the binding for Ninject which will determine which implementation to use:

class Program
 {
 static void Main(string[] args)
 {
 IKernel _Kernal = new StandardKernel();
 _Kernal.Load(Assembly.GetExecutingAssembly());
 ISMSService _SMSService = _Kernal.Get<ISMSService>();

UIHandler _UIHandler = new UIHandler(_SMSService);
 _UIHandler.SendConfirmationMsg("96279544480");

Console.ReadLine();
 }
 }

Now the code is using the Ninject Kernal to resolve all chain of dependencies, if we want to use the real service (SMSService) in Release mode (on production environment) instead of the mock one, we need to change on the Ninject binding class (NinjectBindings) only to use the right implementation or by using the #if DEBUG directive as below:

public class NinjectBindings : Ninject.Modules.NinjectModule
 {
 public override void Load()
 {
#if DEBUG
 Bind<ISMSService>().To<MockSMSService>();
#else
 Bind<ISMSService>().To<SMSService>();
#endif

}
 }

Now our binding class (NinjectBindings) is living on the top of all our execution code and we can control the configuration easily in once place.


Also, see What is Inversion of Control? some very simple examples are mentioned to understand IoC.