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 from lukewarrendev.co.za 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

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.

Want to thank me?

If I've helped you out and you want to thank me, why not buy me a coffee?

Paul Seal

A .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.

Web: codeshare.co.uk

Comments

Share Top