651.288.7000 info@intertech.com

In my last post 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 Data Layer 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:

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.

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:

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:

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:

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:

And the corresponding interface:

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.

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:

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:

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

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:

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:

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:

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.

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.

Summary

Using the Inversion of Control 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.

Like What You've Read?

Subscribe to the Blog.

Every Friday we send that week's content from our Developers via email. Try it out!

Some ad blockers can block the form below.

You have Successfully Subscribed!

Pin It on Pinterest

Share This