What is Dependency injection?

Dependency injection is a technique used for resolving dependencies by using inversion of control, it helps you write better code and makes your code more testable in Unit Tests.

 

What is a Unit Test?

A unit test is a small method which is set up to call some of the code you have written and check the outcome against what your were expecting it to return.

Here is an example unit test taken from an open source project called Rework, which Luke Warren created.

using NUnit.Framework;
using Rework;
using System;

namespace UnitTests
{
    [TestFixture]
    public class RangeTests
    {
        [Test]
        public void Before_WithDateBefore_ReturnsTrue()
        {
            var dateToCheck = new DateTime(2016, 01, 01);
            var dateToUse = new DateTime(2016, 01, 02);
            bool result = Range.Before(dateToCheck, dateToUse);

            Assert.IsTrue(result);
        }
    }
}

Why do we need Dependency Injection?

If your code relies on a service outside of your class, like the MembersService in Umbraco, you can't test the code properly in a unit test. You don't have control over the MembersService and you have to rely it running and being available at the time of calling.  Your unit test will be in a separate library to your web application so it won't have the same context.

 

OK, you've convinced me. How do I set it up?

Watch this video to see me setting it up live with the help of my friend Luke Warren from South Africa

 

Watch on YouTube

Here is how to get it set up in your Umbraco MVC application:

Install the NuGet packages Autofac and Autofac.WebAPI2 in your web project

PM> Install-Package Autofac.Mvc5
PM> Install-Package Autofac.webApi2

2. Add this event handler somewhere in your web project. I created an EventHandlers folder and added this class:

using Autofac;
using Autofac.Integration.Mvc;
using System.Reflection;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using Umbraco.Core;
using Umbraco.Core.Services;
using Umbraco.Web;
using Umbraco.Web.PublishedCache;
using OnlineWishList.Library.Helpers;
using Autofac.Integration.WebApi;

namespace OnlineWishList
{
    public class OnlineWishListEventHandler : IApplicationEventHandler
    {
        #region IApplicationEventHandler Implementation

        public void OnApplicationInitialized(UmbracoApplicationBase application, ApplicationContext context)
        {
        }

        public void OnApplicationStarting(UmbracoApplicationBase application, ApplicationContext context)
        {
        }

        public void OnApplicationStarted(UmbracoApplicationBase application, ApplicationContext context)
        {
            var builder = new ContainerBuilder();

            // Register all controllers found in this assembly
            builder.RegisterInstance(ApplicationContext.Current).AsSelf();
            builder.RegisterControllers(Assembly.GetExecutingAssembly());
            builder.RegisterApiControllers(typeof(UmbracoApplication).Assembly);// Web API

            // Add types to be resolved
            RegisterTypes(builder, context);

            // Configure Http and Controller Resolvers
            var container = builder.Build();
            var resolver = new AutofacWebApiDependencyResolver(container);// web api
            GlobalConfiguration.Configuration.DependencyResolver = resolver; // web api
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
        }

        #endregion

        #region Private Helpers

        private static void RegisterTypes(ContainerBuilder builder, ApplicationContext applicationContext)
        {
            builder.RegisterInstance(applicationContext.Services.MemberService)
                .As<IMemberService>();
            builder.RegisterType<Members>()
                .AsSelf();
        }

        #endregion
    }
}

Notice the highlighted section.

I am registering the MembersService to be injected in whenever I use the interface IMemberService, I am also registering my Members helper class to be used as well.

Add a private property and a constructor to the Surface Controller

private readonly Members _memberHelper;

// We are injecting our dependencies via the constructor using the strategy pattern
// It is important that we register an instance of the Members class and whatever dependencies
// The Members class has in our Event Handler
// That way the DependencyResolver can create it for us
public RegisterController(Members memberHelper)
{
   _memberHelper = memberHelper;
}

Add a constructor for the Helper class to give it the memberService

private readonly IMemberService _memberService;

public Members(IMemberService memberService)
{
    _memberService = memberService;
}

public bool EmailAddressExists(string emailAddress)
{
    IMember member = _memberService.GetByEmail(emailAddress);
    return member != null && member.Email == emailAddress;
}

You're all set

That's all you need to get started. Now you can write your code without relying on state and services running. This will enable you to write tests.

Special Thanks to Luke Warren

I am very grateful to my friend Luke Warren from lukewarrendev.co.za for helping me get set up with this. Make sure you check out his site to see more about test driven development and other MVC, C#, Umbraco and .NET topics.

Paul Seal

Umbraco MVP and .NET Web Developer from Derby (UK) who specialises in building Content Management System (CMS) websites using MVC with Umbraco as a framework. Paul is passionate about web development and programming as a whole. Apart from when he's with his wife and son, if he's not writing code, he's thinking about it or listening to a podcast about it.

Proudly sponsored by

Moriyama

  • Moriyama build, support and deploy Umbraco, Azure and ASP.NET websites and applications.
AppVeyor

  • CI/CD service for Windows, Linux and macOS
  • Build, test, deploy your apps faster, on any platform.
elmah.io

  • elmah.io is the easy error logging and uptime monitoring service for .NET.
  • Take back control of your errors with support for all .NET web and logging frameworks.
uSync Complete

  • uSync.Complete gives you all the uSync packages, allowing you to completely control how your Umbraco settings, content and media is stored, transferred and managed across all your Umbraco Installations.
uSkinned

  • More than a theme for Umbraco CMS, take full control of your content and design with a feature-rich, award-nominated & content editor focused website platform.
UmbHost

  • Affordable, Geo-Redundant, Umbraco hosting which gives back to the community by sponsoring an Umbraco Open Source Developer with each hosting package sold.