Breaking Down Dependency Injection and Inversion of Control in C# with SimpleInjector

For years Dependency Injection and Inversion of Control seemed like buzz words to me. I would constantly hear about them at conferences and meetups when discussing testing and maintainability, though they always seemed to evade me. Part of it may have been imposter syndrome convincing me I wasn't quite there yet. If you try to search these terms, you'll find the equivalent of technical texts and various framework pages explaining how to implement them in their specific flavor. For years, I lacked a clear definition of what these two patterns were; even after I had been using them for some time. I understand the how, but not necessarily the what or the why.

In this post, we are going to take a look at what Dependency Injection and Inversion of Control are at their core; which is that they are design patterns. If you're new to development, hopefully these explanations can help you make sense of these patterns and how you can benefit from them.


Dependency Injection

First, it is important to understand that Dependency Injection and Inversion of Control aren't necessarily synonymous. Both are best described as design patterns, and both can be utilized independently. It is extremely unlikely that you'll find use of the Inversion of Control pattern without the use of the Dependency Injection pattern; though you could see Dependency Injection without a clear use of Inversion of Control.

With that in mind, let's take a quick look at an example of Dependency Injection and develop a foundation before we go any futher.

Take the User class below...

    using System;

    namespace DependencyInjectionExample.Models
    {
        public class User
        {
            public User(string firstName, string lastName)
            {
                FirstName = firstName;
                LastName = lastName;
            }

            public string FirstName { get; set; }
            public string LastName { get; set; }
        }
    }

Believe it or not, User is actually using a form of dependency injection. By accepting a firstName value and lastName value in the constructor, we are effectively saying that the creation of a User is dependent upon these values. Given that we have no default constructor (which is parameterless), you are unable to create a User without these values.

Let's look at a slightly more complex example. The Repository class below requires the use of a function in our DateTimeHelper class when updating a User.

    using System;

    namespace DependencyInjectionExample.Repositories
    {
        public class UserRepository
        {
            private readonly DateTimeHelper _dateTimeHelper = new                         DateTimeHelper();

            public UserRepository()
            {
            }

            public bool Update(User user)
            {
                user.LastModifiedOn = _dateTimeHelper.Format(DateTime.Now);

                ...

                return response;
            }
        }
    }

Within a private field, we are instantiating a new DateTimeHelper so we can call Format() in the Update User method. This is perfectly acceptable code, though if we wanted to unit test any method in this Repository, we'd hit some snags. Since the "newing" up of the DateTimeHelper is happening within the UserRepository, when we call Update in our unit test, we will be using the real implementation of Format(). This could present some issues, since the DateTimeHelper may have it's own dependencies. One of those dependencies could be the System Clock, for example. Meaning that our unit tests may only be valid at certain times of the day, which is far from ideal.

If we use the Dependency Injection pattern, we can make the UserRepository more testable. Let's take a look...

    using System;

    namespace DependencyInjectionExample.Repositories
    {
        public class UserRepository
        {
            private readonly DateTimeHelper _dateTimeHelper;

            public UserRepository(DateTimeHelper dateTimeHelper)
            {
                _dateTimeHelper = dateTimeHelper;
            }

            public bool Update(User user)
            {
                user.LastModifiedOn = _dateTimeHelper.Format(DateTime.Now);

                ...

                return response;
            }
        }
    }

We are passing an instance of DateTimeHelper into the constructor, therefore saying that UserRepository is dependent upon DateTimeHelper.

In the calling code, we may see a line such as this:

    var userUpdated = new UserRepository(new DateTimeHelper()).Update(user);

We are instantiating a new DateTimeHelper to satisfy the constructor of UserRepository. By doing so, we are actually inverting control over the dependencies for the UserRepository.

Inversion of Control

In the previous example, instead of creating a new DateTimeHelper within the UserRepository, we are pushing control of creating this dependency out to the calling code. This allows us to easily mock a DateTimeHelper and use that to create a new UserRepository for testing.


If you would like more information on unit test mocking, I highly recommend NSubstitute.


Let's break it down a litle further...

A dependency is any object or class we are "newing" up in another object or class. In the example of the UserRepository, our dependency is the DateTimeHelper. The injection is happening when we insert that dependency as an argument in the constructor, otherwise known as constructor injection. The Inversion of Control in this example is happening inherently through our use of constructor injection. We are no longer "newing" up the DateTimeHelper directly in the UserRepository. We have inverted control of the instantiation to the calling code, which could be any other class or controller (if you're using ASP.NET or a similar web framework).

Inversion of Control is a difficult pattern to grasp on it's own. That is why you will typically hear of an "IoC Container" or Inversion of Control Container to coincide with this pattern. The true IoC isn't happening in our constructor injection; it occurs when we utilize one of the many (albeit initially confusing) frameworks mentioned in the foreword.

IoC Container

The use of IoC Containers is extremely prevalent in modern frameworks. Microsoft has even baked their own into the newest versions of ASP.NET. These containers can be thought of like vessels or factories. They accept an input, and produce an output. In a way, they're kind of like inventory management for your applications dependencies.

As we discussed earlier, dependency injection moves all of your dependent classes/objects into the constructor. When we eventually instantiate that code, we have to pass a bunch of new instances of things into that object. This could continually chain, as one class is dependent upon another, and so on.

Even though we talked about constructor injection providing a form of inversion of control earlier, these IoC Containers are the true source of inversion. With one of these containers, we can abstract the instantiation of any of these dependencies to a single class (re: container).

There are many of these containers available, such as Castle Windsor, StructureMap, Autofac, and Ninject, but my container of choice has been SimpleInjector.

SimpleInjector

SimpleInjector is my go to IoC Container because, well, it's simple.

I've found it far easier to wrap my head around when it comes to configuration and tracing dependency trees than any of the alternatives. It's also pretty lightweight, and they have published NuGet packages for ASP.NET MVC, WebAPI, and other web frameworks.


Let's take a look at the UserRepository calling code again, and let's assume it's part of an ASP.NET MVC Controller.

    using Microsoft.AspNetCore.Mvc;

    namespace DependencyInjectionExample.Controllers
    {
        public class UserController : Controller
        {
            [HttpPost]
            public IActionResult Update(string id)
            {
                var userUpdated = new UserRepository(new                                     DateTimeHelper()).Update(user);

                ...
                
                return View();
            }
        }
    }

Our calling code could potentially get pretty messy, now that we're going to be "newing" up a bunch of new objects and classes. If we implement an IoC Container, we can abstract that "newing" up out even further, again inverting the control.

Instead of the Update ActionResult being responsible for "newing" up that DateTimeHelper, we can move that into the constructor of our controller.

    using Microsoft.AspNetCore.Mvc;

    namespace DependencyInjectionExample.Controllers
    {
        public class UserController : Controller
        {
            private readonly DateTimeHelper _dateTimeHelper;
            
            public UserController(DateTimeHelper dateTimeHelper)
            {
                _dateTimeHelper = dateTimeHelper;
            }
            
            [HttpPost]
            public IActionResult Update(string id)
            {
                var userUpdated = new UserRepository(_dateTimeHelper).Update(user);

                ...
                
                return View();
            }
        }
    }

The Controller is now responsible for instantiating the DateTimeHelper and we have a readonly reference we can use throughout our Controller. But within ASP.NET MVC, we don't actually instantiate controllers, so how will the UserController get a reference to the DateTimeHelper?

That's where SimpleInjector comes in. Within ASP.NET MVC, the startup method is within the Global.asax file. Here is an example of creating a SimpleInjector container:

    using System.Web.Mvc;
    using SimpleInjector;
    using SimpleInjector.Integration.Web;
    using SimpleInjector.Integration.Web.Mvc;

    protected void Application_Start(object sender, EventArgs e) {
        var container = new Container();

        container.Register<DateTimeHelper>();

        container.RegisterMvcControllers(Assembly.GetExecutingAssembly());

        container.Verify();

        DependencyResolver.SetResolver(new                                           SimpleInjectorDependencyResolver(container));
    }

By creating a new Container and then registering DateTimeHelper, we are essentially creating a contract for the IoC Container "factory", which says; anytime one of my constructors asks for a DateTimeHelper, go ahead and create a new instance to one and inject it in there. Or, if we were using the RegisterSingleton<>() function of the SimpleInjector Container, it would give us a reference to the single instance of that class that is already in memory. We can even Register multiple classes that are dependent upon each other (assuming we register them in the correct order).

    using System.Web.Mvc;
    using SimpleInjector;
    using SimpleInjector.Integration.Web;
    using SimpleInjector.Integration.Web.Mvc;

    protected void Application_Start(object sender, EventArgs e) {
        var container = new Container();

        container.Register<DateTimeHelper>();
        container.Register<UserRepository>();

        container.RegisterMvcControllers(Assembly.GetExecutingAssembly());

        container.Verify();

        DependencyResolver.SetResolver(new                                           SimpleInjectorDependencyResolver(container));
    }

Which allows us to refactor our controller to:

    using Microsoft.AspNetCore.Mvc;

    namespace DependencyInjectionExample.Controllers
    {
        public class UserController : Controller
        {
            private readonly UserRepository _userRepository;
            
            public UserController(UserRepository userRepository)
            {
                _userRepository = userRepository;
            }
            
            [HttpPost]
            public IActionResult Update(string id)
            {
                var userUpdated = _userRepository.Update(user);

                ...
                
                return View();
            }
        }
    }

SimpleInjector creates a dependency map that it uses to navigate through our request of using a UserRepository to determine it also needs to give us a DateTimeHelper.

Not only does the use of a library like SimpleInjector clean up our calling code, but makes all of our code more testable. With IoC like the above example, we can even easily test our ASP.NET Controllers. The use of Dependency Injection and IoC Containers helps to push our codebases closer to 100% test coverage, all while creating more readable code (if implemented properly, of course).

For more information on SimpleInjector, take a look at their docs, which do an excellent job of speaking to all experience levels:

http://simpleinjector.readthedocs.io/en/latest/index.html


To learn more about making your code even more testable through the use of interfaces and mocking, as well as a wide variety of other topics related to C# and .NET, head over to the Cross Cutting Concerns blog and the C# Advent Calendar.