Dependency Injection: Going Start to Finish With Unity in C#
Cari Carpenter, Accusoft Senior Software Engineer
In several previous (and popular) posts on this blog, we examined what dependency injection is and the "why" behind using it (maintainability, testability, flexibility, and extensibility, to name a few). We also looked at our team's journey as we evaluated and discerned which dependency injection container to use with our projects, with Unity being one of the forerunners and the option we ultimately chose. The purpose of this blog post is to take you from step one all the way through a full Unity implementation so that you can use it as a template for your own application.
Required for this setup: Visual Studio, C#, Nuget
Having just taken the plunge of saying "I do" and walking down the aisle five weeks ago, the reader will perhaps forgive me for the fact that our template project for the purpose of this post will be a WeddingPlanner application. Currently there are only two main areas of functionality available to the consumer of the WeddingPlanner application—a Guest Service and an Invitation Service. (Catering, photography, venue, and other wedding planning details will be released in WeddingPlanner 1.2.)
The WeddingPlanner application has a Service layer, a Business layer, a Data Object layer for objects used throughout the solution, a Data Access (Repository) layer, and a test project for each—similar to our company's pilot Unity implementation. The scaffolding for the project looks like this:
In the above structure, the dependencies are as follows:
- In the Service layer, each service is dependent upon its corresponding Business layer manager class. This layer requests data and allows the Data Access and Business layers to retrieve and act upon the data before returning it to the service, which then returns the results to the consumer.
- In the Business layer, each manager class is dependent on its corresponding Data Access layer repository. This layer requests data from the Data Access layer and acts upon it (performs business logic, or simply passes it along) to the Service layer.
- The Data Access layer has no injected dependencies. This layer serves up the requested data to be acted upon (or simply passed along) by the Business layer and returned through the Service layer.
Let's take a look at what that means for our Invitation functionality as far as our constructors go in each layer:
Recall that the Service and Business layers are the only layers that have dependencies; the Data Access layer has none. Thus, the constructor for our InvitationRepository is an empty constructor.
Now that we have an idea of how our WeddingPlanner application is structured in regard to dependencies, let's add Unity into the mix for dependency injection magic. We have an inside joke on our team that certain development tasks should take "only 15 minutes." Let's see if this bears out with our current undertaking.
Unity is Microsoft's dependency injection framework and is available as a Nuget package, as shown below, and should be installed on the Service layer in our current scenario:
Unity allows us to manage our application's dependencies by registering, resolving, and disposing of them via an inversion of control (IoC) container. It is best practice to have a single method that performs this registration and ensure that this is done early in the application's lifecycle.
A common way to achieve this is to create an abstract BaseFactory class from which the Service layer factories derive. This class has an abstract method RegisterTypes that each of the service factories must implement to "tell" the application how to resolve its dependencies. Let's see what this looks like under the hood.
Note the Container.Resolve
InvitationServiceFactory (Derived Class) Implementation
All DI containers essentially do the same thing—register, resolve, and dispose of dependencies. Line 12 above basically says, in plain English, "Every time I give you this interface (IInvitationManager), give me this concrete class (InvitationManager)." Each of the Service layer factories look exactly like this one, except they deal with their respective dependencies. Once you have resolved all dependencies in this way, you've completed the implementation of Unity.
After setting up the initial project, implementing Unity was a matter of simply installing the Unity Nuget package, fleshing out the BaseFactory class, and registering the dependencies in each of the two service factories.
Team BB8 will be proud to know that this took only 14 minutes.
Cari enjoys her role as a Senior Software Engineer on the BB8 Team at Accusoft. She is passionate about test-driven development and XP practices, team dynamics, and mentoring. Follow her on Twitter: @thecodergirl.