Click here to Skip to main content
15,891,136 members
Articles / Programming Languages / C#

Putting It All Together – DI Part 4

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
28 Feb 2014CPOL3 min read 5.7K   2  
Putting It All Together – DI

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.

C#
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:

C#
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:

ECommerce2_Rose

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:

ECommerce_dependencies

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.

This article was originally posted at http://www.larsmichael.net?p=80

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
Denmark Denmark
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.

Comments and Discussions

 
-- There are no messages in this forum --