What is Ninject and when do you use it?

I helped a few friends in the project, and there is a class that uses Ninject. I am new to C # and I have no idea what this class does, so I need to understand Ninject. Can someone explain what Ninject is and when it uses it (with an example, if possible)? Or, if you can point out some links that will be good too.

I tried this question: Ninject tutorials / documentsations? but it didnโ€™t help a beginner like me.

+49
c # dependency-injection ninject
Jun 28 '13 at 23:49 on
source share
3 answers

Ninject is a dependency injector for .NET, a practical implementation of the Injection Dependency pattern (a form of inversion of the 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:

  • To use it, you must initialize _repository . You have such methods:

    • In the constructor manually. But what if the DbRepository constructor changes? You need to rewrite the Controller class because another part of the code has been changed. It is not difficult if you have only one Controller , but if you have a couple of classes that depend on your Repository , you have a real problem.
    • You can use a service locator or factory or smth. Now you have a dependency on your service locator. You have a global service locator, and all the code should use it. How do you change the behavior of a service locator when you need to use one code in one part of the code activation logic and something else in another part of the code? There is only one way - to pass the service locator through the constructors. But with more classes you will need to go through more and more. In any case, this is a good idea, but it is a bad idea.

       class Controller { private DbRepository _repository; public Controller() { _repository = GlobalServiceLocator.Get<DbRepository>() } // ... some methods that uses _repository } 
    • You can use dependency injection. Take a look at the code:

       class Controller { private IRepository _repository; public Controller(IRepository repository) { _repository = repository; } } 

    Now that you need your controller, you write: ninjectDevKernel.Get<Controller>(); or ninjectTestKernel.Get<Controller>(); . You can switch between dependent converters as fast as you want. See? It's simple, you donโ€™t have to write a lot.

  • You cannot run unit tests on it. Your Controller is dependent on DbRepository , and if you want to test any method that uses the repository, your code will go to the database and request data from it. It is slow, very slow. If your code in DbRepository changes, your unit test on Controller will DbRepository . In this case, only the integration test should say "problems." What you need in unit tests is to isolate your classes and test only one class in one test (ideally, only one method). If your DbRepository code failed, you will think that the Controller code failed - and this is bad (even if you have tests for DbRepository and Controller ), they will both fail and you can start from the wrong place). It takes a long time to determine where the error is. You need to know that some class is OK and another class has failed.

  • If you want to replace DbRepository with something else in all your classes, you need to work hard.

  • You cannot easily manage the lifetime of a DbRepository . An object of this class is created when the Controller initializes and is deleted when the Controller 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(); 

And a special feature of dependency injection is its flexible development! You describe that your controller uses a repository with the IRepository interface. You do not need to write a DbRepository , you can write a simple MemoryRepository class and develop a Controller , while other guys are developing a DbRepository . When the DbRepository is complete, you simply IRepository default IRepository DbRepository in your dependency DbRepository . Have you scored a lot of controllers? All of them will now use DbRepository . It's great.

More details:

+44
Jun 29 '13 at 0:42 on
source share

Ninject is the inverse of the Control container.

What is he doing?

Suppose you have a Car class, which depends on the Driver class.

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

To use the Car class, you create it like this:

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

A holding IoC centralizes knowledge on how to create classes. This is a central repository that knows a few things. For example, he knows that the specific class that you need to use to build the car is Driver , and not any other IDriver .

For example, if you are developing an MVC application, you can tell Ninject how to create controllers. You do this by registering which specific classes satisfy certain interfaces. At runtime, Ninject will figure out which classes are needed to create the required controller, and everything is behind the scenes.

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

This is useful because it allows you to create systems that are easier to test per unit. Suppose Driver encapsulates all database access for Car . In the unit test for a 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 whole frameworks that take care of automatically creating test classes for you, and they are called mocking frameworks.

For more information:

+34
Jun 29 '13 at 0:06 on
source share

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

Here is a snippet of the article:

Below the Interface will be implemented by ours (SMSService) and (MockSMSService), basically the new interface (ISMSService) will expose the same behavior of both services in the form of code below:

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

(SMSService) to implement the interface (ISMSService):

 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 a completely 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 for our class constructor (UIHandler) to pass a dependency through it, using this code that uses (UIHandler), it can determine which specific implementation (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 need to create a separate class (NinjectBindings), which inherits from (NinjectModule). This class will be responsible for resolving dependencies at runtime, and then override the load event that is used to configure the binding in it. The good thing about Ninject is that we donโ€™t 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 the user interface form code, use the link 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 uses Ninject Kernal to solve all the chains of dependencies, if we want to use a real service (SMSService) in Release mode (in a production environment) instead of a mock one, we need to change to Ninject (NinjectBindings) only to use the correct implementation or using the #if directive DEBUG as shown 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) lives at the top of our entire execution code, and we can easily manage the configuration in one place.




Also see What is control inversion? Some very simple examples are mentioned for understanding IoC.

+2
Feb 21 '17 at 18:57
source share



All Articles