Implementing the DI Containers

January 04, 2018

DI (Dependency Injection) Container/IoC (Inversion of Control) Container

DI Container or IoC container are the terms that are used interchangeably but have the same meaning.

What is it?

Consider using the following code to instantiate a class with multiple services:
var instance = new Class1(new Service1(), new Service2(new Service3()), new Service4());


nesting of dependencies in dependency injection


Will you prefer using the code as the one above?
The answer would be NO as this is really fussy and confusing code to find out what is actually going on here.

To solve the above problem, we use the DI Container, that helps us simplify the above code to human readable and understandable extent.

Definition

A DI Container is a framework that automatically creates the objects and injects the dependencies when required.
To simplify the fuss related to creating instances( sometimes nested ) and injecting them, we use the DI container.

With a DI Container used, the code will look something like:
var instance = container.Resolve<Class1>();

But how to implement this?

This can be well explained with this detailed example below.
There are a lot of DI Container frameworks in the market like Unity, Castle Windsor, StructureMap, Ninject etc. I will be using the Unity DI Container for this example.

Installing Unity DI Container

We will install Unity DI Framework with the Unity's NuGet package. To install the NuGet package, follow these steps:
Step 1: Right-click the project name in the solution explorer and Click on "Manage NuGet Packages"

Step 2: With the browse option selected, search for "Unity" and click on the download icon against it. Click Ok if you are prompted for installation.


Implementing the Unity DI Container
Consider a class Class1 such that it needs a dependency Dependency1. The class Dependency1 needs another dependency class Dependency2.
class Class1 
{
    IDependency1 dependency1;
    public Class1(IDependency1 dependency)
    {
        dependency1 = dependency;
    }
}

class Dependency1 
{
    IDependency2 dependency12

    public Dependency1(IDependency2 dependency)
    {
        dependency2 = dependency;
    }
}
So the class object instantiation would look like:
Class1 instance = new Class1(new Dependency1(new Dependency2()));
Thus creating a nested dependency in the instantiation of the Class1 object.
But this object instantiation looks a bit confusing and we need to sort this out.

Implementing the DI Container

Let's start using Unity DI Container.
In our C# console application, first we need to import the Unity Namespace by adding a following reference to the import statements:
using Unity;

Now we need to register the types that will be injected whenever we need a service/dependency like whenever we need a IDependency1 service, the DI container will automatically inject the Dependency1 class instance.

The syntax for registering the mapping between the type of object to be received and the actually needed object is:
var container = new UnityContainer();

container.RegisterType<IClass1, Class1>();
container.RegisterType<IDependency1, Dependency1>();
container.RegisterType<IDependency2, Dependency2>();

All statements look similar. So what do these statements mean?
Let's look at it.

The format is something like:
container.RegisterType<RequiredType, SuppliedType>();
i.e. whenever an object of a IClass1 is required, the instance of Class1 object will be automatically passed by the DI Container.

Now instead of instantiating Class1 object as:
var instance = new Class1( new Dependency1( new Dependency2() ) );

With the use of DI Container, I will simply instantiate Class1 object as:
var instance = container.Resolve<IClass1>();

The Container instance provides a resolve method that will automatically resolve the dependency and will supply the instance of Class1. Since Class1 further have IDependency1 needed, the DI Container will automatically pass a new instance of Dependency1 and so on.

The final Code for the C# Console application will look like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Unity;

namespace ConsoleApp1
{
    class Class1 : IClass1
    {
        IDependency1 dependency1;

        public Class1(IDependency1 dependency)
        {
            dependency1 = dependency;
        }
    }

    class Dependency1 : IDependency1
    {
        IDependency2 dependency2;

        public Dependency1(IDependency2 dependency)
        {
            dependency2 = dependency;
        }
    }

    class Dependency2 : IDependency2
    {
    }

    class Program
    {
        static void Main(string[] args)
        {
            var container = new UnityContainer();

            container.RegisterType<IClass1, Class1>();
            container.RegisterType<IDependency1, Dependency1>();
            container.RegisterType<IDependency2, Dependency2>();

            var instance = container.Resolve<IClass1>();

            Console.ReadKey();
        }
    }
}

You Might Also Like

0 comments