Dependency Injection and IoC in .NET with Unity

Introduction

Dependency Injection in .NET is not a complicated concept to understand and implement; however when working on projects with other developers I often see them using the new keyword to create a dependant object (i.e. concrete class), rather than using the dependency injection design pattern alongside interfaces, and its a code smell to me personally when I see the new keyword in a constructor of a class.

This is mostly prevalent to me when working on n-tier enterprise applications when developers are instantiating a new layer (class object) in their code (typically in the constructor). Even smaller applications tend to grow in my experience when customers require changes or enhancements.

What they are doing is making their code less maintainable, harder to unit test, difficult to refactor, lack of flexibility when providing alternative service implementations (proxy classes), and going against most of the SOLID design principles through making the classes “Tightly Coupled”.

Let’s have a look at some good and bad examples

Let me give you an simple example without dependency injection which I commonly see:

public class TaskManager
{
    private readonly TaskDataManager taskDataManager;

    public TaskManager()
    {
       this.taskDataManager = new TaskDataManager();
    }
}

What this code is achieving is basically stating that the TaskManager class has a direct dependency on the TaskDataManager class, as it creates a new TaskDataManager object within its own constructor.

1. The TaskManager class is responsible for creating its own dependencies within its constructor which is bad practice (i.e. it is giving the class too much responsibility). When a class instantiates its own dependencies directly it typically knows too much about the class(s) its dependant on, its implementation, and the code within it. You also lose a possible extension point using this method which an interface would provide by default.

2. We could never use an alternative ‘Data Manager’ class now within this ‘Manager’ class as we have specified the specific TaskDataManager concrete class.

3. We can’t unit test the TaskManager class without having to also use the TaskDataManager class by default as they are so tightly coupled.

If the TaskDataManager class was implemented to update records in a database, then our unit tests of the TaskManager class would therefore also update our database every time we ran them..(not good!) This tight coupling to me is like:

Designing a washing machine that will only work with one particular brand of washing powder..

4. If the TaskDataManager class also as a direct dependency on a concrete class called TaskService then by default the TaskManager class also has this concrete dependency to the TaskService class. This is how the Entourage anti-pattern manifests itself which leads to a huge web of connected dependencies which if very difficult to refactor and maintain.

Let’s have a look at the same piece of code but now using dependency injection and interfaces:

public class TaskManager: ITaskManager
{
    private readonly ITaskDataManager TaskDataManager;

    public TaskManager(ITaskDataManager taskDataManager)
    {
       this.TaskDataManager = taskDataManager;
    }
}

Now that we have re-factored the code to use interfaces and dependency injection we have removed the issues/limitations that we had previously as:

1. The TaskManager class now has its dependencies injected into it’s constructor rather than creating its dependencies itself; and its no longer responsible for locating its own dependencies.

2. The TaskManager class now only has a dependency on an interface of type ITaskDataManager which means we could inject any alternative service class that implements this interface. (The TaskManager class only relies on a behaviour rather than a specific implementation/code). An example would be swapping out the TaskDataManager class which for example sent emails; to be a different class which implements ITaskDataManager which could send text messages instead.

3. We could now unit test the TaskManager class in isolation by injecting a mock TaskDataManager class into its constructor i.e. a class that implements ITaskDataManager.  This mock class would use stubs rather than an actual implementation against a database; so we could run the unit tests over and over again without affecting actual data in the database.

4. The TaskManager class now does not have a direct dependency on the TaskService (which is a dependency of the TaskDataManager) The TaskManager class depends only on a generalised interface with abstract behaviour and nothing further.

Using Inversion of Control (IoC) and DI to resolve dependencies

Microsoft define Inversion of Control and Dependency Injection as (link):

Inversion of Control (IoC) means that objects do not create other objects on which they rely to do their work. Instead, they get the objects that they need from an outside source (for example, an xml configuration file).

Dependency Injection (DI) means that this is done without the object intervention, usually by a framework component that passes constructor parameters and set properties.

Looking at the code above you may be wondering how and where the application maps the interfaces to concrete classes, as it is not possible to create an instance of an interface? If we were to try and use the updated classes above as they are Visual Studio would loudly tell you that it is not possible and your application will fall over.

Inversion of Control (IoC) allows you to defer the construction of dependencies until run time; usually through the use of IoC containers using third party code. IoC containers facilitate the mapping of interfaces to concrete classes by resolving the dependencies for you at run time; typically in code or configuration files which are bootstrapped in the application entry point. Any time your application encounters an interface it will know which concrete instance it needs to resolve.

There are many products by various vendors which you can use for this purpose such as Microsoft Unity, Ninject and AutoFac. In this post we are going to use Unity as it is part of the Microsoft Best Practice and Patterns suite.

How to use Unity for IoC and Dependency Injection

Dependency Injection is where Microsoft Unity comes into its own. Unity is described by Microsoft as:

Unity is Microsoft’s Patterns and Practices solution for DI. The Unity Container (Unity) is a lightweight, extensible dependency injection container. It facilitates building loosely coupled applications and provides developers with the following advantages:

Simplified object creation, especially for hierarchical object structures and dependencies

Abstraction of requirements; this allows developers to specify dependencies at run time or in configuration and simplify management of crosscutting concerns

Increased flexibility by deferring component configuration to the container

Service location capability; this allows clients to store or cache the container

Instance and type interception

Registration by convention

Installing Unity through Nuget in Visual Studio will add the Unity libraries to your project, as well as a UnityConfig.cs file. This will allow us to register all of the dependencies at run time rather than concrete dependencies in code.

There are different nuget packages for Unity depending on your application type, such as Windows Forms, Web API or MVC; but they largely work in the same manner, just bootstrapping the container in a different place.

An example of a UnityConfig file for our examples in the previous section could be the following:

public static void RegisterTypes(IUnityContainer container)
{
    container.RegisterType<ITaskService, TaskService>();
    container.RegisterType<ITaskDataManager, TaskDataManager>();
    container.RegisterType<ITaskManager, TaskManager>();
}

The code above would ensure that when the application is started all of the dependencies with regards to our interfaces would be resolved to their concrete counterparts, for example ITaskDataManager to TaskDataManager.

Although this is a very simple example to describe the concepts, Unity has many powerful features such as object lifetime resolution which is beyond the scope of this post. Microsoft provide a great set of documents on Unity as part of its Best Practice and Patterns which can be viewed here if you would like to take the example further: https://msdn.microsoft.com/en-us/library/dn223671(v=pandp.30).aspx

Summary

I hope this article is enough to wet the appetite of developers that are currently not using dependency injection in their .NET code; describing how to make their code more adaptive, and giving just enough information to get them going. For further information on IoC and DI I encourage you to read Martin Fowler’s website which can be accessed here.

Leave a comment