14 Nov 2016
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.
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); } } }
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.
Watch this video to see me setting it up live with the help of my friend Luke Warren from South Africa
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 } }
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.
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; }
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; }
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.
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.