Click here to Skip to main content
15,888,195 members
Articles / Programming Languages / C#
Technical Blog

Implementing Dependency Injection using Ninject

Rate me:
Please Sign up or sign in to vote.
4.89/5 (15 votes)
8 Nov 2013CPOL6 min read 91.1K   23   11
How to implement dependency injection using Ninject

Introduction

I’ve been always asked by fresh grads who joined our development team a very basic question: “Why do we have to code against Interfaces not against concrete implementations?”. And to answer this question, we start an interesting talk about the benefits of writing loosely coupled classes, and how to write unit tests without changing implementation, then this leads us to talk about Dependency Injection (DI) and Inversion of Control (IoC) which I find it a little bit complicated topic to grasp from the first time.

So in this post, I will briefly explain why we use Dependency Injection and how we can implement it using Ninject as Inversion of Control framework.

The source code of this demo is available on github.

Dependency Injection Definition?

DI is a software design pattern which allows the removal of hard-coded dependencies between classes and allows to change them at run-time. In other words, it allows you to load mock classes in test environments v.s real objects in production environments (Wikipedia).

How dependencies are created? Let’s see an example

Suppose we are building an application which contains a feature to send SMS confirmation messages once the order has been shipped. In an Object Oriented world, it is very important to adhere to Separation of Concerns pattern, so in our situation we will have two classes, one is responsible for sending the SMS (SMSService), and another responsible for capturing user inputs (UIHandler), our code will look as below:

C#
public class SMSService
 {
  public void SendSMS(string mobileNumber, string body)
        {
            SendSMSUsingGateway(mobileNumber, body);
        }

        private void SendSMSUsingGateway(string mobileNumber, string body)
        {
            /*implementation for sending SMS using gateway*/
        }
 }

public class UIHandler
 {
 public void SendConfirmationMsg(string mobileNumber) {

 SMSService _SMSService = new SMSService();

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

This implementation is not wrong, and I’ve been doing it in past many times, but now we are tightly coupling and creating dependencies between the two classes. The (UIHandler) depends on (SMSService) once we instantiated an object from it. By looking at this example, we can easily identify the issues that might appear if we want to implement the below scenarios:

  • On development environment, you want to save SMSs sent to a text file instead of using SMS gateway, to achieve this; we will end up changing the concrete implementation of (SMSService) with another implementation, we are losing flexibility and forced to rewrite the code in this case.
  • We’ll end up mixing responsibilities of classes, our (UIHandler) should never know about the concrete implementation of (SMSService), this should be done outside the classes using “Interfaces”. When this is implemented, it will give us the ability to change the behavior of the system by swapping the (SMSService) used with another mock service which implements the same interface, this service will save SMSs to a text file.

How do we overcome dependencies issue? Let’s see an example:

We need to fix our code and to use Interfaces which will be implemented by our (SMSService) and the new (MockSMSService), basically the new Interface (ISMSService) will expose the same behaviors of both services as the code below:

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

Then we will change our (SMSService) implementation to implement the (ISMSService) interface:

C#
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);
 }
 }

Now we will be able to create new mock up service (MockSMSService) with totally different implementation using the same interface:

C#
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);
 }
 }

At this point, we can change the code in (UIHandler) to use the concrete implementation of the service (MockSMSService) easily as below:

C#
public class UIHandler
 {
 public void SendConfirmationMsg(string mobileNumber) {

 ISMSService _SMSService = new MockSMSService();

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

We have achieved a lot of flexibility and implemented separation of concerns in our code, but still we need to do a change on the code base to switch between the two SMS Services. So we need to implement manual Dependency Injection without using any IoC framework.

To achieve this, 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:

C#
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 the UI form which will talk with class (UIHandler) is responsible to pass which implementation of interface (ISMSService) to consume. This means we have inverted the control, the (UIHandler) is no longer responsible to decide which implementation to use, the calling code does. We have implemented the Inversion of Control principle which DI is one type of it.

The UI form code will be as below:

C#
class Program
 {
 static void Main(string[] args)
 {
 ISMSService _SMSService = new MockSMSService();

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

Console.ReadLine();
 }
 }

This type of manual Dependency Injection is good and it will work perfectly, but what will happen if our project gets more complicated and the number of dependencies have increased? As we will see in this post, we will add a new service (NotifierService) which will be responsible to send email notification for users once the order is shipped. Once this service is added, you will end up adding new constructor parameter for every new dependency in the class you are instantiating to implement DI manually. So in this situation, we need to use Dependency Injection framework such as Ninject.

How to use Ninject in your project?

We need to download Ninject library which is compatible with our .NET Framework 4.5, or you can use Nuget in Visual Studio to download the package “Ninject”. I’m a fan of NuGet, so I will install the packages below using Package Manager Console:

PM> Install-Package Ninject

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).

There are different ways to implement injection patterns (Constructor Injection, Property Injection, and Method Injection), we’ll use the primary DI pattern which is Constructor Injection.

C#
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:

C#
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:

C#
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.

Real life scenario with more injected dependencies:

This is cool so far, but in real life scenario we’ll barely have only one service to interact with, let we assume that we will introduce another service (NotifierService) which is responsible for notifying customer by email that order has been shipped.

The (NotifierService) will be called inside the (SMSService) which means that (SMSService) depends on (NotifierService) to execute, our code will be as given below:

C#
public class SMSService : ISMSService
 {
 private readonly INotifierService _NotifierService;

public SMSService(INotifierService NotifierService)
 {
 _NotifierService = NotifierService;
 }

public void SendSMS(string mobileNumber, string body)
 {
 SendSMSUsingGateway(mobileNumber, body);
 _NotifierService.NotifyByEmail(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);
 }
 }

Now in Ninject bindings, we need to add a new binding for service (NotifierService) to the load event, the code will be as below:

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

}
 }

Now we can see how easy it is to add new dependencies and inject them at run-time without making code changes to our classes, our code now is loosely-coupled, highly-cohesive, and ready for writing unit tests.

The source code of this demo is available on github.

For more advanced scenarios, you can check Ninject website and Christiaan blog.


License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect App Dev Consultant
Jordan Jordan
Working for Microsoft Consultation Services as a Lead App Dev Consultant.

I have more than 15 years of experience in developing and managing different software solutions for the finance, transportation, logistics, and e-commerce sectors. I’ve been deeply involved in .NET development since early framework versions and currently, I work on different technologies on the ASP.NET stack with a deep passion for Web API, Distributed systems, Microservices, and Microsoft Azure.

Prior to joining Microsoft, I have been awarded the Microsoft Most Valuable Professional (MVP) Award for the years 2015 and 2016 in Visual Studio and Development Technologies, also I’m a regular speaker in local events and Dev user groups.

Comments and Discussions

 
QuestionParameters in UI constructor Pin
A M SOMAN14-Mar-19 0:16
A M SOMAN14-Mar-19 0:16 
QuestionNinject.WebForms (load failed) Pin
Roger C Moore1-Mar-17 4:43
Roger C Moore1-Mar-17 4:43 
QuestionThanks for code via Github Pin
Ravi Sant22-Sep-16 5:37
Ravi Sant22-Sep-16 5:37 
Github. That was real quick and easy than to download code. Thanks.
// ♫ 99 little bugs in the code,
// 99 bugs in the code
// We fix a bug, compile it again
// 101 little bugs in the code ♫


Tell your manager, while you code: "good, cheap or fast: pick two. "

QuestionGot basic need of DI Pin
Ravindra Gojare21-Jul-16 1:50
Ravindra Gojare21-Jul-16 1:50 
QuestionNice and simple Pin
NaibedyaKar19-Jun-16 10:00
professionalNaibedyaKar19-Jun-16 10:00 
QuestionGood start with ninject Pin
Jersondev4-Nov-15 11:11
Jersondev4-Nov-15 11:11 
GeneralFinally a good and simple tutorial for NInject Pin
NN---6-Oct-15 7:41
NN---6-Oct-15 7:41 
Questionthank you so much Pin
javad.ghamari9-Aug-15 11:15
professionaljavad.ghamari9-Aug-15 11:15 
GeneralVery good and clear read !!! Pin
arrnvid6-Feb-15 9:42
arrnvid6-Feb-15 9:42 
QuestionLimited to one class per interface? Pin
Member 106493436-Mar-14 9:48
Member 106493436-Mar-14 9:48 
AnswerRe: Limited to one class per interface? Pin
DavidFreire8-Mar-15 17:34
DavidFreire8-Mar-15 17:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.