651.288.7000 info@intertech.com

In my I talked about resolving dependencies at the top most layer by simply instantiating dependencies.  In this post we will look at using a dependency injection library.  We will be looking at demonstration code (meaning I don’t always follow good coding practices such as exception handling and robust return types from the API) so I am going to describe the application and show a bit of this simplified code.

The Dependency Injection Demonstration Application

Say I have an application that needs to accept a web request and write a message to some persistence medium – I chose an azure queue but it could have just as easily been a database or the file system.  In a different process I need to run a potentially long running process to consume the messages on the queue.  I am going to take a layered approach for this design.

Starting With the Data Layer

If we look at our layers starting with the I have a couple classes.  The AzureQueue class is there because I want to hide the fact that we are working with an Azure specific queue from the consumers.  To do this I apply the Adapter pattern.  My goal when designing this class was to make sure all properties and methods exposed primitive types or interfaces. I am not designing this class so it may be tested in isolation rather I am designing this class so other classes that depend on it may be tested in isolation.  Here is the code:

using Intertech.Interfaces;
using Microsoft.WindowsAzure.Storage.Queue;
using System.Threading.Tasks;

namespace Intertech.Data
{
    //thin wrapper to act as an adapter for the Azure Queue
    //Consider this "untestable" in isolation of a real queue
    public class AzureQueue : IQueue
    {
        private Azure.Queue queue;
        private CloudQueueMessage message;
        public AzureQueue()
        {
            queue = new Azure.Queue();
        }
        public async Task DeleteMessageAsync()
        {
            await queue.DeleteMessageAsync(message);
        }
        public async Task<IQueueMessage> DequeueMessageAsync()
        {
            message = await queue.DequeueAsync();
            return new QueueMessage(message.Id, message.AsString);
        }
        public async Task EnqueueAsync(string message)
        {
            await queue.EnqueueAsync(message);
        }
    }
}

Notice in the constructor I am using a static method to get a reference to a helper object that knows how to access the Azure queue.  Also note that the class implements the IQueue interface and the only .Net types the caller needs to be aware of are string and IQueueMessage.

The QueueMessage class is also an adapter on top of the CloudQueueMessage which is the (somewhat complex) type used to push/pop messages on the Azure queue.

using Intertech.Interfaces;

namespace Intertech.Data
{
    public class QueueMessage : IQueueMessage
    {
        public QueueMessage(string id, string message)
        {
            Id = id;
            Message = message;
        }
        public string Id { get; }
        public string Message { get; }
     }
}

Again note all return types are primitive and the class implements the IQueueMessage interface.  This is really just a DTO that can be used to communicate the idea of a message from layer to layer.  For the sake of completeness here are the Interfaces (located in an assembly of their own:

using System.Threading.Tasks;

namespace Intertech.Interfaces
{
    public interface IQueue
    {
        Task DeleteMessageAsync();
        Task<IQueueMessage> DequeueMessageAsync();
        Task EnqueueAsync(string message);
    }
    public interface IQueueMessage
    {
        string Id { get; }
        string Message { get; }
    }
}

Next, the Business Layer

The next layer up is the Business Layer.  I have a single simple class designed to Process Messages.  It looks like this:

using Intertech.Interfaces;
using System.Threading;
using System.Threading.Tasks;

namespace Intertech.Business
{
    public class MessageProcessor : IMessageProcessor
    {
        internal virtual async Task<bool> IsValid(IQueueMessage message)
        {
            if (!(message.Message.Length < 32000))
            //Do things like deserialize message
            //Validate customer exists
            //look for a bad message format
            //log why message is invalid
            //simulate some work executing
            await Task.Run(() => Thread.Sleep(5000));
            return true;
            
        }
        public virtual async Task<bool> ProcessMessage(IQueueMessage message)
        {
            if (! await IsValid(message)) return false;
            //simulate some work executing
            await Task.Run(() => Thread.Sleep(5000));
            return true;
        }        
    }
}

Not much for implementation but this is where we will be writing code to execute a long running process.  Again notice the class is implementing an interface and taking care to only expose primitives or abstract types as parameter and return types.  This is a theme – we do this so we can test this and dependents of this in isolation.

Here is the interface –  in a different assembly:

using System.Threading.Tasks;

namespace Intertech.Interfaces
{
    public interface IMessageProcessor
    {
        Task<bool> ProcessMessage(IQueueMessage message);
    }
}

The Service Layer Orchestrates Interaction Between the Business and Data Layer

Next up is the Service Layer.  This layer understands how the Business Layer and Data Layer need to interact so it’s reason for being here is to orchestrate that interaction.  Here is the code:

using Intertech.Interfaces;
using System;
using System.Threading.Tasks;

namespace Intertech.Service
{
    public class MessageService : IMessageService
    {
        private IQueue queue;
        private IMessageProcessor processor;
        public MessageService(IQueue queue, IMessageProcessor processor)
        {
            this.queue = queue;
            this.processor = processor;
        }

        public async Task<bool> PersistMessage(string message)
        {
            await queue.EnqueueAsync(message);
            return true;
        }

        public async Task<bool> ProcessMessage()
        {
            try
            {
                var result = await queue.DequeueMessageAsync();
                await processor.ProcessMessage(result);
                await queue.DeleteMessageAsync();
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
    }
}

And the corresponding interface:

using System.Threading.Tasks;

namespace Intertech.Interfaces
{
    public interface IMessageService
    {
        Task<bool> PersistMessage(string message);
        Task<bool> ProcessMessage();
    }
}

You do not have to understand all of the above code at this point, you only need to understand that the various classes use primitives and interfaces on all methods and all dependencies are injected via constructor injection.  It is these dependencies we will resolve using a dependency injection library.

Dependency Resolution Without the Dependency Injection Library

Lets first look at dependency resolution without the dependency injection Library.  Here is my web job, notice the second line of code I am instantiating 3 different objects.  This is not terrible code, especially because object instantiation is trivial here but the class is responsible for resolving dependencies and calling the message processor until there is no more work.  This is a Single Responsibility Principle (SRP) violation.

using Intertech.Business;
using Intertech.Data;
using Intertech.Interfaces;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Intertech.WebJob
{
    class Program
    {
        static void Main(string[] args)
        {
            int i = 1;
            IMessageService service = new Service.MessageService(new AzureQueue(), new MessageProcessor());
            Task.Run(async () =>
            {
                while (await service.ProcessMessage())
                {
                    Console.WriteLine($"Processing message: {i}");
                    i++;

                }
            }).Wait();

            Thread.Sleep(5000);
        }
    }
}

Here is my controller which is responsible for resolving dependencies, and forwarding messages to a layer that will write them to a repository, also an SRP violation:

using Intertech.Business;
using Intertech.Interfaces;
using Intertech.Service;
using System.Threading.Tasks;
using System.Web.Http;

namespace QueueInput.Controllers
{
    public class MessagesController : ApiController
    {
        private IMessageService service;
        public MessagesController()
        {
            service = new MessageService(new Intertech.Data.AzureQueue(), new MessageProcessor());
        }
                // POST: api/Messages
        public async Task Post([FromBody]string value)
        {
            await service.PersistMessage(value);
        }
    }
}

DEPENDENCY RESOLUTION WITH THE DEPENDENCY INJECTION LIBRARY

Which dependency injection library you choose is up to you, there are a bunch of good ones out there.  for the purposes of this post I am going to use Simple Injector a free open source library.

To install Simple Injector for my web job (which is a console app), from the Package Manager Console enter the following:

Install-Package SimpleInjector

Now I modify my code to look like this:

using Intertech.Business;
using Intertech.Data;
using Intertech.Interfaces;
using Intertech.Service;
using SimpleInjector;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Intertech.WebJob
{
    class Program
    {
        static void Main(string[] args)
        {
            int i = 1;
            var container = new Container();
            Bootstrap.Start(container);
            IMessageService service = container.GetInstance<IMessageService>();
            Task.Run(async () =>
            {
                while (await service.ProcessMessage())
                {
                    Console.WriteLine($"Processing message: {i}");
                    i++;

                }
            }).Wait();

            Thread.Sleep(5000);
        }
    }

    class Bootstrap
    {
        public static void Start(Container container)
        {
            // Register your types, for instance:
            container.Register<IMessageService, MessageService>(Lifestyle.Transient);
            container.Register<IMessageProcessor, MessageProcessor>(Lifestyle.Transient);
            container.Register<IQueue, AzureQueue>(Lifestyle.Transient);

            // Optionally verify the container.
            container.Verify();
        }
    }
}

Notice I have introduced a bootstrap class.  This is the class where I register my abstractions with the corresponding concrete implementation.  For example,

container.Register<IMessageService, MessageService>(Lifestyle.Transient);

The above code tells simple injector that when a service implementing IMessageService is requested – provide the MessageService concrete type.  Now I still need code in my Main method to initialize the container so for a console application it is not a huge SRP win but I was able to separate object construction logic and the app code.  The key bit of code here is that rather than instantiating the MessageService, I ask the container to do it for me:

IMessageService service = container.GetInstance<IMessageService>();

Things get even more clean with the Web API.  To install Simple Injector for Web AP from the package manager console:

Install-Package SimpleInjector.Integration.WebApi.WebHost.QuickStart

Using this version of the package, some code is going to be added to the project for us:

[assembly: WebActivator.PostApplicationStartMethod(typeof(QueueInput.App_Start.SimpleInjectorWebApiInitializer), "Initialize")]

namespace QueueInput.App_Start
{
    using System.Web.Http;
    using SimpleInjector;
    using SimpleInjector.Integration.WebApi;
    using Intertech.Interfaces;
    using Intertech.Service;
    using Intertech.Business;

    public static class SimpleInjectorWebApiInitializer
    {
        /// <summary>Initialize the container and register it as Web API Dependency Resolver.</summary>
        public static void Initialize()
        {
            var container = new Container();
            container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
            
            InitializeContainer(container);

            container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
       
            container.Verify();
            
            GlobalConfiguration.Configuration.DependencyResolver =
                new SimpleInjectorWebApiDependencyResolver(container);
        }
     
        private static void InitializeContainer(Container container)
        {
            // Register your types, for instance:
            container.Register<IMessageService, MessageService>(Lifestyle.Transient);
            container.Register<IMessageProcessor, MessageProcessor>(Lifestyle.Transient);
            container.Register<IQueue, Intertech.Data.AzureQueue > (Lifestyle.Transient);
        }
    }
}

The top line of code tells a nuget package called WebActivator to run the SimpleInjectorWebApiInitializer.Intitialize method when the IIS App domain starts.  the only code I added to the class is inside the InitializeContainer methods.  This is where we map our abstractions to the concretions.

With this logic in place I can modify my controller as follows.  Notice the constructor injection on the Messages controller:

using Intertech.Interfaces;
using System.Threading.Tasks;
using System.Web.Http;

namespace QueueInput.Controllers
{
    public class MessagesController : ApiController
    {
        private IMessageService service;
        public MessagesController(IMessageService service)
        {
            this.service = service;
        }
                // POST: api/Messages
        public async Task Post([FromBody]string value)
        {
            await service.PersistMessage(value);
        }
    }
}

For the MessageController to be instantiated we need an object that implements the IMessageService interface passed to the constructor.  Simple injector takes care of that for us. Simple injector also understands that to Instantiate the MessageService, it needs to resolve the IQueue and IMessageProcessor at construction time as well and it takes care of all of that for us too.

This is a nice clean controller.  The only reason we would need to change this is if we need to change what aspects of the message service are exposed to the outside world in the API.  The only reason we would need to change the SimpleInjectorWebApiInitializer class would be to change or add Interface to concretion mappings.

A quick note on the lifetime of the objects that Simple Injector resolves for us.  Notice when I map an interface to the concrete implementation I am passing a “LifeStyle” argument.

container.Register<IMessageService, MessageService>(Lifestyle.Transient);

This argument tells simple injector that when you request a IMessageService it should behave in a Transient manor which is that a new instance of the component is returned everywhere the service is requested or injected.  If I refactor my message service such that it is stateless, I can benefit by it being a singleton.  Via registration, I can tell Simple Injector to manage the MessageService as a singleton for me.

container.Register<IMessageService, MessageService>(Lifestyle.Singleton);

Summary

Using the Design Principle, we have made our classes more loosely coupled and therefore easier to test. Using a dependency Injection library we have better applied the Single Responsibility Principle and it also allows us to do some pretty powerful object scoping without having to write code.  Applying this principle is a lot of work and so far I suspect the benefit is not obvious.  In my next posts we will look at some different techniques for testing code that makes use of the Inversion of Control Design Principle, this is where all of this design work will pay off.