Click here to Skip to main content
15,867,890 members
Articles / Programming Languages / C#

A Curry of Dependency Inversion Principle (DIP), Inversion of Control (IoC), Dependency Injection (DI) and IoC Container

Rate me:
Please Sign up or sign in to vote.
4.96/5 (142 votes)
17 Oct 2016CPOL23 min read 231.3K   1.2K   280   92
Description of DIP, IoC, DI, IoC container and how to use them in real life work

Contents

Introduction

Welcome to my post. Here, I will try to describe DIP, IoC, DI and IoC container. Most of the time, beginner developers face problems with DIP, IoC, DI and IoC Container. They mix-up all together and find it difficult to identify the difference between them and don’t know why they need to use them. On the other hand, lots of people use DI, IoC without knowing it and what problem it solves. There are many posts, articles, blogs available on this topic but not all together. Here, I have tried to describe all together. I hope after reading my post, the reader will be able to identify the difference between DIP, IoC, DI & IoC Container/framework, also know how and when to use them. I also hope after reading my post, readers will able to create their own IoC container. Before going into details, let me describe DIP, IoC, DI and IoC container using simple sentences.

Dependency Inversion Principle (DIP) Principle used in architecting software
Inversion of Control (IoC) Pattern used to invert flow, dependencies and interfaces
Dependency Injection (DI) Implementation of IoC to invert dependencies
IoC Container Framework to do dependency injection. It helps to map dependencies, manage object creation & lifetime.

Background

DIP is a software design principle and IoC is a Software design pattern. Let's see what is Software design principle and pattern.

  • Software design principle: Principle provides us guideline. Principle says what is right and what is wrong. It doesn’t tell us how to solve a problem. It just gives some guidelines so that we can design good software and avoid bad design. Some principles are DRY, OCP, DIP, etc.
  • Software design pattern: Pattern is a general reusable solution to a commonly occurring problem within a given context in software design. Some patterns are factory pattern, Decorator pattern, etc.

Now we have everything for going into details.

So principle defines good and bad. So we can say if we maintain principle during software design, then it will be good design. If we don’t maintain principle, then we may fall into problems. Now we are only focusing on Dependency Inversion Principle (DIP) which is D on SOLID principle.

Dependency Inversion Principle (DIP)

Instead of lower level modules defining an interface that higher level modules depend on, higher level modules define an interface that lower level modules implement.

Let's Try to Understand DIP with Some Example

Image 1

Let try to describe the above principle with simple example of portable charger or devices. Consider you have Camera, Phone and other devices. These devices use cable to connect with computer or charger. A simple jack or port is used to connect with computer or charger, right? Now if you are asked who has defined the port or jack; cable or your device?

You definitely answer device. Based on device port varies. So from the story, what we found is that port doesn’t define what will be the device but device defines what will be port or jack.
So software modules are similar. High level module defines the interface and low level module implements that interface and low level module doesn’t define interface like jack doesn’t define the device.
Let's again consider the DIP according to Bob Martin's definition:

A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
B. Abstractions should not depend upon details. Details should depend upon abstractions.

So from the principle, we can say high level module should not depend on low level module. Both depend on abstraction. Abstraction should not depend on low level.

Let's Try to Understand DIP with Some Example

Case 1: Dependency not inverted (High level module depends on low level interface)

Image 2

From the figure, we found high level depends on low level interface. So high level class needs to think about all the interfaces. When new low level class comes, then again high level class needs to change which makes complexity on maintenance and it violates open close principle.

Case 2: Dependency Inversion

Image 3

Now see the figure. Here, higher level class defines the interface and higher level class doesn’t depend on lower level class directly. Lower level classes implements interface defined by higher level class so higher level class doesn’t need to change when new implementation arrived.

Case 3: A Copy program without DIP

Image 4

Consider the above example:

  1. First, ignore dotted objects. You have a copy program which is responsible for taking input from keyboard and writing to text file. Your current copy program can maintain both of them so it doesn’t makes problem.
  2. Now consider after a certain period, your boss asked you to develop your copy program so that it can store reading data to database. Then what will you do. You will again change to copy program so that it can write to database. This will increase the complexity of your program.

Case 4: Copy Program with DIP

Image 5

If we consider the above example, then we find that the copy program is dependent on reader interface and writer interface defined by copy program. So it is directly not dependent on lower level classes like read from scanner, write to printer, etc. As a result, we don’t need to change the copy program when a new requirement will come and our copy program is independent.

I think DIP is little bit clear. Now let’s see what will be the benefit for maintaining DIP and problems for not maintaining DIP. If we don’t maintain software design principle, then our software design will be bad design. Now consider a software design where we didn’t maintain Dependency Inversion Principle (DIP). As we are not maintaining DIP, then we will have a problem. Let's see.

Problems We Will Face if We Do Not Maintain DIP

  • System will be rigid: It will be difficult to change a part of the system without affecting too many other parts of the system.
  • System will be fragile: When we will make a change, unexpected parts of the system will break.
  • System or component will be immobile: It will be difficult to reuse it in another application because it cannot be disentangled from the current application. And so on…

Benefit of Maintaining DIP

First thing is we can solve the above problems. That means our system will be loosely coupled, independent, modular, testable and so on. As DIP is a principle, it does not say how to solve the problem. If we want to know how to solve the problem, then we have to move on to Inversion of Control.

Inversion of Control (IoC)

DIP doesn’t tell us how to solve the problem but Inversion of Control defines some way so that we can maintain DIP. It is the thing which you can practically apply on your software development. Lots of definition available for IoC. Here I just try to give a simple definition so that we can easily understand.

What is IoC

IoC helps us to apply DIP. In simple IoC is Inverting the control of something by switching who control. Particular class or another module of the system will be responsible for creation object from outside. Inversion of control means we are changing the control from the normal way.

IoC and DIP

Image 6

DIP says High level module should not depend on low level module and both should depend on abstraction. IoC is a way that provides abstraction. A way to change the control. IoC gives some ways to implement DIP. If you want to make independent higher level module from the lower level module, then you have to invert the control so that low level module is not controlling interface and creation of the object. Finally, IoC gives some way to invert the control.

Splitting IoC

We can split IoC in the following ways. (Description will be provided later.)

  • Interface Inversion: Inverting interfaces
  • Flow inversion: Invert the flow of control and it is the foundation idea of IoC which is similar to, "Don’t call us, we will call you."
  • Creation Inversion: This is mostly used by developers. We will use it when we go to DI and IoC container.

Fitting Altogether (DIP, IoC and DI)

Image 7

I am not making full curry here. Just consider the above image how everything together fits. This is the view how all things fit together. DI is not only the way of Dependency creation that’s why I have used “….” . There are many ways to implement Dependency creation. Here, I am just interested in DI. That’s why I have shown it in the figure and others are doted. At the top is DIP which is a way of designing software. It doesn’t sys how to make independent module. IoC provides some way of applying DPI principle. IoC doesn’t provide specific implementation. It gives some methods so that we can invert the control. If we want to invert control using Binding inversion or dependency creation, then we can achieve it by implementing dependency injection (DI).

Interface Inversion

Interface inversion is the inversion of interface. Consider a Reader application. This reader application is read from text file.

Image 8

Now consider this application also read from pdf and word file:

Image 9

Creating too many interface doesn’t mean I am implementing IoC or maintaining DPI. What is the benefit of using too many interfaces? Here we have no benefit because every time we have to change our reader class and reader class had to maintain all the interfaces. So ultimately we are not benefited. Now we have a method called interface inversion. Let invert the interfaces.

Image 10

By considering the above example, we remove all the interfaces from lower level classes and make single interface defined by reader class. What we did here just invert the interface. Now we have lots of benefit. We don’t need to change reader class anymore and reader class is independent. Now consider above thing as a provider model.

Image 11

Flow Inversion

Let’s see something about flow inversion. Flow inversion is the simple inversion which is backbone of the IoC. If you think about normal flow then you will find it is procedural.

Normal Flow

Image 12

Figure: Command line program

Consider a command line program which first asks for your name then you put your name, again it will ask for your age then you will provide your age. What is going on here? You found your command line application executes one by one that means basic flow is procedural. It goes step by step.

Inverted Flow

Now let’s try to invert the flow. Now we can think about a GUI. Consider our GUI consists of two input box one for user name and another for user age. Just consider the following figure:

Image 13

Figure: GUI Program

Now you see you can provide your name and your age without maintaining flow. If you want you can put your age first and your name last. So you don’t need to depend on basic flow. On the other hand when you press save button, then your program saves information. In command line program you are asking for first do this, then do this but in GUI flow is controlled by user.

Creation Inversion

This is most familiar inversion of control method and we are going to use it on IoC container. Now consider the following.

In a normal way, how can we create an object:

C#
Class A
{
  YourClass yourObject = new YourClass();
}

So you are creating object which is dependent on another class and makes system tightly coupled. Here you are creating the object from inside your current class.

Now consider Interface Inversion:

C#
Class A
{
    IYourInterface yourObject = new YourClass();
}

Even we are using interface inversion still we creating object inside the class. So creation of the object still has dependences. So what is creation inversion? What things we have to do to break the dependences? Let's see...

Inverting Control/ Creation Inversion

Creating object outside of the class they are being used in. We are making object from outside of the class so higher level class is not directly depending on lower level class. Now let’s see why we need to invert the control.
Consider you have a GUI and you want to place a button on a screen. Your button has many design so your UI shows button based on UserSettings. Now what will be our code if we are doing in a normal way. Let's see.

C#
Button btn;
switch (UserSettings.ButtonStyle)
{
    case "Metro": btn = new MetroButton();
        break;

    case "Office2010": btn = new Office2007Button();
        break;

    case "Fancy": btn = new FancyButton();
        break;
}

So from the code, our UI will show different style button based on user settings. Now after a certain period, new styles come, then again you have to change UI code. If 20 style comes, then we have to change 20 times. As Creation inversion says, we have to create object outside of the class. Now let's try to follow that.
Now consider we have a FactoryClass (we can learn more by reading factory pattern) which is responsible for providing button object based on user settings. This factory class is responsible for object creation. Now again, let’s see our UI class after implementing ButtonFactory class. Here, I am not describing how to create Button factory class, but you will find details later.

So new UI has the following code:

C#
Button btn = ButtonFactory.CreateButton();

So our button is depending on factory class and we don’t need to change our UI code when a new style comes. Here, object creation is done from outside of the UI class. In this way, we are inverting the creation of object.

Types of Creation Inversion

Factory Pattern

If you check the above example, then you will find that I have managed the creation of object from outside of the UI class. In factory pattern, we do something like:

C#
Button btn = ButtonFactory.CreateButton(); 

Service Locator

C#
Button btn = ServiceLocator.Create(IButtonControl);

In service locator pattern, we are passing interface and corresponding implementation of requested interface will be provided by service locator. Here, I am not describing details because I am only focused on describing Dependency Injection (DI).

Dependency Injection (DI)

In dependency injection, we pass dependency. Consider the following simple code:

C#
Button btn = GetButtonInstanceBasedOnUserSettings();
OurUi ourUI = new OurUi(btn);

Here, we passed the dependencies when creating UI. In DI, the key idea is passing dependencies. DI is not only constructor injection. In the next section, I will describe more details on DI.

More…

There are more way to creation inversion.
So in summary, any time you are taking the dependencies and binding the dependencies out of the class, you are inverting the control and this is treated as Inversion of Control (IoC).

Dependency Injection (DI)

Most of the time, people mix-up DI with IoC. IoC describes different ways of inverting the control. On the other hand, DI inverts the Control by passing dependencies. So here, I will try to describe the following things:

Image 14

  • What is Dependency Injection (DI)
  • Types of DI
  • Constructor Injection
  • Setter Injection
  • Interface Injection

What is Dependency Injection

A type of IoC where we move the creation and binding of dependency outside of the class that depends on it. Normally, objects are created inside of the dependent class and bounded inside the dependent class. In DI, it is done from outside of the dependent class. Let us consider an example:

Image 15

Figure: Tiffin box with breakfast

Suppose you bring a Tiffin box to your office for breakfast. So you bring everything that you needed to breakfast. So you are managing the breakfast by Tiffin box. This is similar to creation object inside of the class in a sense you are managing what you needed.

Image 16

Figure: Your breakfast will be provided like the above image

Now consider another example. In your office, breakfast will be provided. You don’t need to bring the Tiffin box with you. Then what will happen. Still you can have breakfast but now it is provided by the office. This is similar to DI where the required object is provided outside of the class.

Types of Dependency Injection

Constructor Injection

This is the most common form DI. Pass dependencies to dependent class through constructor. An injector creates the dependencies and passes the dependencies through constructor. Let's consider the following example. We have a PurchaseBl class which is responsible for performing save operation and depends on IRepository.

C#
public class PurchaseBl
{
    private readonly IRepository _repository;

    //Constructor
    public PurchaseBl(IRepository repository)
    {
        _repository = repository;
    }

	public string SavePurchaseOrder()
    {
        return  _repository.Save();
    }
}

Now let's see how we will access this PurchaseBl and how we will pass dependency through constructor:

C#
//Creating dependency
IRepository dbRepository = new Repository();

//Passing dependency
PurchaseBl purchaseBl = new PurchaseBl(dbRepository);

From the above example, we see PurchaseBl depends on IRepository and the PurchaseBl doesn’t directly create any instance of repository. This repository will be provided outside of the class. As a result, our PurchaseBl is independent from lower level class and it provides loose coupling.

Here, Repository class implements IRepository which saves information to database. Now think if you need to save information to TextFile, then you don’t need to change the PurchaseBL class. You just have to pass another TextRepository class which is responsible for saving data to text file. Now let me show you if you have TextRepository class, then how you will pass that repository.

C#
IRepository textRepository = new TextRepository();
PurchaseBl purchaseBl = new PurchaseBl(textRepository);

So you can change dependencies without affecting higher level class PurchaseBl.

Setter Injection

This is another type of DI technique where we pass dependencies through setter instead of constructor. So what do we have to do to setter injection:

Create setter in dependent class: In C#, you just need to create a property. Use that property to set dependencies.

Pass dependences through setter: Here, we can pass dependences through setter. We also create an object of class without passing dependences.

Let us see how I can create setter injection:

C#
public class PurchaseBl
{
   //Property
   public IRepository Repository { get; set; }
  
   //Here, we are not creating any constructor which takes dependencies
   public string SavePurchaseOrder()
   {
      return Repository.Save();
   }
}

Now let’s inject dependency through setter.

C#
//Creating dependency
IRepository dbRepository = new Repository();
PurchaseBl purchaseBl = new PurchaseBl();
//Passing dependency through setter
purchaseBl.Repository = dbRepository;
Console.WriteLine(purchaseBl.SavePurchaseOrder());

It has some flexibility where we can change the dependency after creation of object and also we can create object without dependencies. There is a caution of setter injection. As we can create object without dependencies, then it may through exception when using dependencies without setting/injecting them.

Interface Injection

This is not commonly used and it is complex compared to others. Dependent class implements an interface. Interface has a method signature for setting the dependencies. Injector uses the interface to set dependency. So we can say dependent class has an implementation of interface and has a method to set dependencies instead of using setter and constructor.

Let's see an example.

C#
public interface IDependentOnTextRepository
{
    //Method signature which is liable to inject/set dependency
    void SetDependency(IRepository repository);      
}
C#
public class PurchaseBl :IDependentOnTextRepository
{
    private IRepository _repository;

    public string SavePurchaseOrder()
    {
        return _repository.Save();
    }

    public void SetDependency(IRepository repository)
    {
        _repository = repository;
    }
}
C#
//Creating dependency
IRepository dbRepository = new Repository();
PurchaseBl purchaseBl = new PurchaseBl();
//Passing dependency
((IDependentOnTextRepository)purchaseBl).SetDependency(dbRepository);
  1. First, we have an interface class with a setter method. Let's create that interface.
  2. Dependent class will implement the interface. So according to our example, PurchaseBl will implement IDependentOnTextRepository.
  3. Then finally, let's see how we can use PurchaseBl.

I think this is little bit complex compared to others and not commonly used.

Inversion of Control Container (IoC Container)

What is IoC Container

  • Framework for doing dependency Injection
  • Provides a way to configure dependencies
  • Automatically resolves configured dependencies

Still not clear? Let me describe it in another way. IoC container is a framework to create dependencies and pass them when needed. That means we don’t need to manually create dependencies like earlier examples. IoC framework automatically creates objects based on request and injects them when needed. So it reduces lots of pain. You will be happy when you see all the dependencies created automatically.

What IoC Container Does

  1. Creates dependencies / objects
  2. Pass/Inject dependencies when needed
  3. It manages object life time
  4. It also stores the mapping of classes defined by the developer. Based on this mapping, your IoC container creates object.
  5. And does so many things….

Lots of IoC framework (Unity, Ninject, Castle Windsor, etc.) are available to use. You can download them according to your need. But before using them, I want to create IoC framework myself so that you can understand how IoC framework exactly works. Let’s visualize IoC Container. From the figure:

Image 17

IoC container knows all the classes. IoC knows what are dependencies and who are dependent. When dependent class requests for an object, then IoC provides the instance of requested class based on configuration. If Dependent class requests for a class that implements IRepository, then IoC thinks of what dependencies (DBRepository or FakeRepository) need to provide based on configuration.

Manual Constructor Injection

In Constructor Dependency injection section, I have showed you some example. There, I actually did manual constructor injection. Just recall them:

C#
//Manually Creating dependencies
IRepository dbRepository = new Repository();
//Manually Passing dependencies
PurchaseBl purchaseBl = new PurchaseBl(dbRepository);

Here, I am creating dependency and after creating, I am passing that dependency to high level class. If my high level class is dependent on several low level class, then I had to create several dependencies and pass them manually. Then what does IoC container do? The answer is that the IoC Container automatically creates the dependencies and you don’t need to create them manually. I will show you how to create IoC container and how we can make them automatic and manage them from central point.

Building Own IoC Container

I know lots of IoC containers available but I am showing here how we can develop our own IoC container because it helps to understand how IoC container works. I am not going to show you details of how IoC container is created. Here, I just create a simple IoC container which can resolve dependences based configuration. Let’s start from scratch. Consider we have the following interfaces and implementations.

C#
///<summary>
///A repository interface used for Persisting 
///Persistance media will defined by implementation
///</summary>
public interface IRepository
{
    string Save();
}

And we have following implementation. Repository is responsible for storing data to database and TextRepository is responsible for storing data to text file. Now consider a simple implementation of IRepository:

C#
///<summary>
/// Responsible for saving data to Database
///</summary>
public class Repository : IRepository
{
    public string Save()
    {
        return "I am saving data to Database.";
    }
}
///<summary>
/// Responsible for saving data to text file
///</summary>
class TextRepository : IRepository
{
    public string Save()
    {
        return "I am saving data to TextFile.";
    }
}

Now we have PurchaseBl class which is dependent on IRepository. PurchaseBl is responsible for applying business logic and it uses IRepository to persist its information.

C#
/// This is a class where we put our business logic.
/// Here, we have SavePurchaseOrder method which is responsible for storing data.
/// But this class doesn't know where to store data. 
/// It is just using implementation of IRepository to storing data.

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

    public string SavePurchaseOrder()
    {
        return _repository.Save();
    }
}

Our business class PurchaseBl doesn’t know where data will be stored. So it is not depending on lower level class. We can change the persistence mechanism without changing our business class.

Let's use our PurchaseBl with manual dependency injection first.

C#
public static void Main()
{
   //Creating dependency
   IRepository dbRepository = new Repository();
   //injecting dbRepository
   PurchaseBl purchaseBl = new PurchaseBl(dbRepository);
   Console.WriteLine(purchaseBl.SavePurchaseOrder());
}

Output

I am saving data to Database.

Now if we want to store our data to text file without affecting our Business layer, then we just have to make a little change on dependency creation. Let’s see:

C#
public static void Main()
{
    IRepository textRepository = newTextRepository();
	//Injecting textRepository
    PurchaseBl purchaseBl = newPurchaseBl(textRepository);
    Console.WriteLine(purchaseBl.SavePurchaseOrder());
}

Output

I am saving data to TextFile.

Now we think one step further and want to use IoC Container, then what will our main method look like. Let’s see:

C#
public static void Main()
{
    Resolver resolver = new Resolver();   //Resolver is a IoC container
    PurchaseBl purchaseBl = new PurchaseBl(resolver.ResolveRepository());
    Console.WriteLine(purchaseBl.SavePurchaseOrder());
}

public class Resolver
{
    public IRepository ResolveRepository()
    {
        return new TextRepository();
    }
}

But the above technique is not good enough. Every time, we have to create method on Resolver class which may increase complexity. Now let’s think another step further. We want to resolve dependences like the following:

C#
public static void Main()
{
    Resolver resolver = new Resolver();//Resolver is a IoC container
    PurchaseBl purchaseBl = resolver.Resolve<purchasebl>();
    Console.WriteLine(purchaseBl.SavePurchaseOrder());
}

See that we don’t need to create dependencies. IoC container automatically creates dependences and injects to PurchaseBl class. Now our main method is more simple compared to previous. Am I right? Now our IoC container resolves dependences by reading the type of class. Here, I just showed you how to use IoC container and how to get object by passing the type only. Now let’s create our one. Here, I am adding my simple code with description.

C#
/// <summary>
/// Our simple IoC container
/// </summary>
public class Resolver
{
   //This is dictionary used to keep mapping between classes
   private readonly Dictionary<Type, Type> _dependencyMapping = new Dictionary<Type, Type>();

   /// <summary>
   /// return requested object with requested type
   /// </summary>
   /// <typeparam name="T">Takes type which needs to be resolved</typeparam>
   /// <returns></returns>
   public T Resolve<T>()
   {
       // cast object to resolved type
       return (T)Resolve(typeof(T));
   }

   /// <summary>
   /// This method takes the type which needs to resolve and 
   /// returns an object based on configuration
   /// </summary>
   /// <param name="typeNeedToResolve">takes type which needs to resolve</param>
   /// <returns>return an object based on requested type</returns>
   private object Resolve(Type typeNeedToResolve)
   {
       Type resolvedType;
       try
       {
           //Taking resolved/return type from dictionary 
           //which was configured earlier by Register method
           resolvedType = _dependencyMapping[typeNeedToResolve];
       }
       catch
       {
           //If no mapping found between requested type and 
           //resolved type, then it will through exception
           throw new Exception(string.Format("resolve failed for {0}", 
                                              typeNeedToResolve.FullName));
       }

       //Getting first constructor of resolved type by reflection
       var firstConstructor = resolvedType.GetConstructors().First();

       //Getting first constructor's parameter by reflection
       var constructorParameters = firstConstructor.GetParameters();

       //if no parameter found then we don't need to think about 
       //other resolved type from the parameter
       if (!constructorParameters.Any())
           return Activator.CreateInstance(resolvedType); // returning an instance of 
                                                          // resolved type

       //if our resolved type has constructor, then again we have to resolve that types;
       //so again, we are calling our resolve method to resolve from constructor
       IList<object> parameterList = constructorParameters.Select(
         parameterToResolve => Resolve(parameterToResolve.ParameterType)).ToList();
       //invoking parameters to constructor
       return firstConstructor.Invoke(parameterList.ToArray());
   }

   /// <summary>
   /// This method is used  to store mapping between request type and return type
   /// If you request for IRepository, then what implementation will be returned; 
   /// you can configure it from here by writing
   /// Registery<IRepository, TextRepository>()
   /// That means when resolver requests for IRepository, then TextRepository will be returned
   /// </summary>
   /// <typeparam name="TFrom">Request Type</typeparam>
   /// <typeparam name="TTo">Return Type</typeparam>
   public void Registery<TFrom, TTo>()
   {
       _dependencyMapping.Add(typeof(TFrom), typeof(TTo));
   }
}

So finally, our main method looks like the following:

C#
public static void Main()
{
    //registering dependencies  to Container
    var resolver = new Resolver();
    resolver.Registery<IRepository, FakeRepository>();
    resolver.Registery<PurchaseBl, PurchaseBl>();
    // Resolving dependencies
    var purchaseBl = resolver.Resolve<PurchaseBl>();
    Console.WriteLine(purchaseBl.SavePurchaseOrder());
}

Things You Need to Know to Use IoC Framework

If you think that the above code is complex, then you don’t need to understand it. You just need to know two things for using IoC container.

  1. How to configure dependencies called how to register component
  2. How to resolve dependencies

For resolving object, you just need to write the following code:

C#
//Resolving dependencies
var purchaseBl = resolver.Resolve<purchasebl>;();
Console.WriteLine(purchaseBl.SavePurchaseOrder());

Here, I am not saying anything about object life time management because as I said, I will create a simple IoC container so that you can understand how IoC works.

Now I want to show you how we can use another IoC container Ninject in our project.

Using Ninject IoC Container

Here, I will try to cover:

  • Introduction to Ninject
  • Setting up the container
  • Using Container
  • Lifetime management and other features

Image 18

Ninject

Ninject is a newer open source IoC Container. This is simple and extensible. You can download Ninject IoC container from the following location: http://www.ninject.org/download.html. Or you can use NuGet to add ninject to your project. Let's add ninject to our project from NuGet. Just go to your project reference and right click, then ManageNuGet Packages.. then search for Nintject. You will find something like the following:

Image 19

After installing Ninject, you will find Ninject on project reference. For using Ninject, you have to use following namespace:

C#
using Ninject;

Setting Up the Container

Ninject container uses a class named kernel. Ninject automatically registers all concrete types. You don’t need to register them.

Registering Dependencies

C#
var kernel = new StandardKernel();
kernel.Bind<IRepository>().To<Repository>();

When IRepository will be requested, then Repository implementation will be provided.

Using Container

Resolving Dependencies

C#
//resolving dependencies
//Out from kernel
PurchaseBl purchaseBl = kernel.Get<PurchaseBl>();
Console.WriteLine(purchaseBl.SavePurchaseOrder());

It produces the following output.

Output

I am saving data to Database.

If we change the bindings, then:

C#
var kernel = new StandardKernel();
kernel.Bind<IRepository>().To<TextRepository>();
PurchaseBl purchaseBl = kernel.Get<PurchaseBl>();
Console.WriteLine(purchaseBl.SavePurchaseOrder());

It produces the following output.

Output

I am saving data to TextFile.

Rebind is very useful when we need to do something over default binding. Suppose in some times, we need to change default binding when new modules come. For rebinding, we can use Rebind method like the following:

C#
kernel.Rebind<IRepository>().To<Repository>();

These are simple ways in which we can use ninject. Now let's see how to manage life cycle using ninject.

Object Life Cycle Management Using Ninject

Let's modify our TextRepository class so that we can understand our object life. The following TextRepository is our modified class.

C#
/// <summary>
/// Responsible for saving data to text file
/// </summary>
public class TextRepository : IRepository
{
    private int _counter = 0;
    public string Save()
    {
        _counter++;
        return string.Format("I am saving data to TextFile {0}.", _counter);
    }
}

Let me create two instances of PurchaseBl like the following:

C#
var kernel = new StandardKernel();
kernel.Bind<IRepository>().To<TextRepository();

//resolving dependencies
//Out from kernel
var purchaseBl = kernel.Get<PurchaseBl>();
Console.WriteLine(purchaseBl.SavePurchaseOrder());

var purchaseBl2 = kernel.Get<PurchaseBl>();
Console.WriteLine(purchaseBl2.SavePurchaseOrder());

Now we have two PurchaseOrderBl instances, purchaseBl and purchaseBl2. So the output is:

Output

I am saving data to TextFile1.
I am saving data to TextFile1.

Look here - both outputs showing 1, that means every time it creates new instances. Now if we want to create a single instance of TextRepository, then we have to create instance as a Singleton so that the same instance shares through both purchaseBl and purchaseBl2.

Let's do that:

C#
kernel.Bind<IRepository>().To<TextRepository>().InSingletonScope();

Output

I am saving data to TextFile1.
I am saving data to TextFile2.

Now first one returns 1 and then the second one returns 2 - that means a single instance of TextRepository was shared by both. We can create our object in many scopes like Transaction Scope, Thread Scope, Singleton Scope and so on. These are the basics of how we can use ninject in our project. Later, I have a plan to write more details about ninject, Unity and Castle Windsor.

Conclusion

We write lots of code and after some time, we face difficulties to manage and test them. This is only because of tight coupling. Tight coupling makes our system rigid. DIP, IoC and DI helps us to write loosely couple code and make independent, modular system. Here, we saw lots of ways to make IoC. From all the techniques, Creation inversion (Dependency injection with constructor injection) is very common. I think DIP, IoC, DI and IoC container are now clear to you. I just tried to present altogether here because it helps us to understand all things related to DIP. Just remember one thing - without IDP, you cannot create independent and pluggable system. Here, I cannot describe more details because it will become too large and complicated. Thanks for reading my post!! I am expecting your valuable comments, suggestion and criticism.

Some References

History

  • 7th February, 2013: Initial version

License

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


Written By
Software Developer SELISE
Bangladesh Bangladesh
Hi I am Mohammad Hasibul Haque an application developer. Now I am working as a Software Engineer(.net) at Daffodil Group. Here I am working for Business ERP, Daffodil School Management System and so on. I am dedicated to Microsoft .NET based application development.

I am very much fan of Microsoft. Always want to learn new things & new technologies..

I am Microsoft Certified Professional Developer (MCPD ASP.net .net 3.5) and also achieved Microsoft Community Contributor Award 2011 from Microsoft.

Comments and Discussions

 
QuestionHow to register a Type with parameters? Pin
Member 102159392-Jul-19 21:58
professionalMember 102159392-Jul-19 21:58 
GeneralGreat Article on (DIP), (IoC), (DI) Pin
User-125510844-May-19 4:40
User-125510844-May-19 4:40 
PraiseExcellent Article Pin
Jaheer Syed16-Mar-19 22:06
professionalJaheer Syed16-Mar-19 22:06 
GeneralMy vote of 5 Pin
Mike (Prof. Chuck)19-Feb-19 19:25
professionalMike (Prof. Chuck)19-Feb-19 19:25 
BugWhat IoC is Pin
Orphen9112-Nov-18 1:24
Orphen9112-Nov-18 1:24 
GeneralMy vote of 5 Pin
Bernardo Lopez Stgo30-Jul-18 12:02
Bernardo Lopez Stgo30-Jul-18 12:02 
GeneralMy vote of 5 Pin
Luciano A26-Oct-16 5:42
Luciano A26-Oct-16 5:42 
PraiseGreat overview. Pin
Oleg Lit.21-Oct-16 8:35
Oleg Lit.21-Oct-16 8:35 
GeneralMy vote of 4 Pin
Member 1279853618-Oct-16 9:09
Member 1279853618-Oct-16 9:09 
Bugconflict between your article and wikipedia Pin
Member 1180582523-Aug-16 19:13
Member 1180582523-Aug-16 19:13 
GeneralRe: conflict between your article and wikipedia Pin
Hasibul Haque17-Oct-16 10:15
professionalHasibul Haque17-Oct-16 10:15 
PraiseThank you Pin
game_over31-Jul-16 20:44
professionalgame_over31-Jul-16 20:44 
QuestionDoubt Pin
Bhanu Chhabra15-Jun-16 19:31
Bhanu Chhabra15-Jun-16 19:31 
GeneralMy vote of 5 Pin
D V L9-Sep-15 0:56
professionalD V L9-Sep-15 0:56 
GeneralSuper dude , You done it . Last few days,I am searching for this topic and had gone through many article but most of them even can't convey DI Pin
Member 1180092030-Jul-15 10:05
Member 1180092030-Jul-15 10:05 
QuestionThanks Pin
MikiyasB24-Nov-14 3:01
professionalMikiyasB24-Nov-14 3:01 
AnswerRe: Thanks Pin
Hasibul Haque24-Nov-14 3:22
professionalHasibul Haque24-Nov-14 3:22 
QuestionFull Marks to Article Pin
dhirajonnet7-May-14 19:28
professionaldhirajonnet7-May-14 19:28 
AnswerRe: Full Marks to Article Pin
Hasibul Haque7-May-14 19:33
professionalHasibul Haque7-May-14 19:33 
QuestionWhy do we have to Instantiate Interface to Concrete Class? Pin
Member 845796423-Aug-13 19:53
Member 845796423-Aug-13 19:53 
GeneralMy vote of 5 Pin
kaisernayan18-Aug-13 21:34
kaisernayan18-Aug-13 21:34 
GeneralRe: My vote of 5 Pin
Hasibul Haque18-Aug-13 21:42
professionalHasibul Haque18-Aug-13 21:42 
GeneralMy vote of 5 Pin
_Vitor Garcia_1-Aug-13 0:55
_Vitor Garcia_1-Aug-13 0:55 
GeneralRe: My vote of 5 Pin
Hasibul Haque1-Aug-13 2:05
professionalHasibul Haque1-Aug-13 2:05 
GeneralMy vote of 5 Pin
leiyangge29-Jul-13 6:07
leiyangge29-Jul-13 6:07 

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.