Dependency Injection – and the low coupling between components that it leads to – goes hand in hand with high cohesion. It is now time to grab the individual components and put them together to form a “real” application.
In the first post in this series, it was explained how the whole point of dependency injection is to remove the burden of composing objects away from the individual components themselves, and instead delegate this responsibility to a single well-defined location as close as possible to the entry point of the application – also denoted the composition root of the application.
This object composition can very well be done manually by simply “newing” up all the objects – which is sometimes referred to as “poor man’s DI” – but a good alternative is to leave the responsibility of solving the object graph to a DI container. A DI container is a third-party library that can automate the object composition and lifetime management. Furthermore, some DI containers support runtime interception which is a very powerful technique for solving cross-cutting concerns such as logging or authorization (more about this in a later post).
And yes, when using a DI container you are, ironically enough, introducing a new dependency to solve the dependencies! But obviously, the DI container object itself should be created manually, and the DI container library should only be referenced from the composition root.
Anyway, here is an example of wiring up the application using Microsoft’s DI container called Unity in an ASP.NET MVC application. Adding a reference to the Unity.Mvc3
library (for example using the NuGet Package Manager) will automatically create a static
helper class called Bootstrapper
. In the BuildUnityContainer()
method, you need to register which concrete type should be mapped to the IRepository<Product>
abstraction during run time. In this case, an XmlProducRepository
class is used. XmlProductRepository
itself has a dependency to a string
defining the path to the XML file used as physical repository.
public static class Bootstrapper
{
public static void Initialise()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(
new UnityDependencyResolver(container));
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
container.RegisterType<IRepository<Product>,
XmlProductRepository>(new
InjectionConstructor(@"c:\data\repository.xml"));
return container;
}
}
To use ProductService
in one of the controllers (e.g. the HomeController
), you need to inject ProductService
using constructor injection:
public class HomeController : Controller
{
private readonly ProductService productService;
public HomeController(ProductService productService)
{
this.productService = productService;
}
public ActionResult Index()
{
var list = new List<string>();
foreach (var product in this.productService.GetAll())
{
list.Add(string.Format(@"{0}: USD {1:0.00}",
product.Name, product.Price));
}
ViewBag.Products = list;
return this.View();
}
}
That’s it. The DI container takes care of the rest.
The first time you are introduced to the concept of DI containers, you might become a bit mystified, and even worried, about all the “magic” that apparently goes on behind the scenes. I certainly know that I was. However, trying to dig a bit deeper into what actually goes on might help on this scepticism. This is what happens during an incoming request to go to the Home page of the application:
MvcApplication
receives a request to go to the Home page. The DependencyResolver
is asked to resolve HomeControler
(i.e., create the whole object graph) – and this is where the magic starts! The dependency resolver detects the dependencies (HomeControler
-> ProductService
-> IRepository<Product>
-> string
) and starts creating the object graph from the bottom and up. First, an instance of ProductRepository
is created. During registration, you declared that this was the concrete type to be used for the IRepository<Product>
abstraction. You also declared the path to the physical file “c:\data\repository.xml” during registration. Then this ProductRepository
instance is injected into ProductService
, using constructor injection, when creating the ProductService
instance. Finally, this ProductService
instance is injected into the HomeController
when creating the HomeController
instance. The dependency resolver has done its job for this incoming request.
Subsequently, the Index()
method of the HomeControler
is called and the HomeController
can use the injected ProductService
to retrieve a list of products, which can then be displayed in the browser.
This is how the dependency graph of your application looks:
MvcApplication
(found in the Global.asax
file) acts as the composition root taking care of object composition. The business component has no dependencies to other components, so the Dependency Inversion Principle is still respected.
I am a software architect/developer/programmer.
I have a rather pragmatic approach towards programming, but I have realized that it takes a lot of discipline to be agile. I try to practice good craftsmanship and making it work.