Main menu

Kickass kung fu coder

Tag Archives: IoC

Introduction

This post continues from this previous post. In this post I will be creating a ASP.NET MVC application using the architecture described in the previous post. I will start by laying out the requirements, driving out the behaviour through tests, implement Unity and create the layers for the UI, controller and Presentation Processes.

Since writing my previous post, I have came across a blog which contains some really good tips / best practices for ASP.NET MVC, which I recommend you read.

Requirements

So to start, we need requirements as development should be driven by requirements. In business analyst language, this is the requirement that i will be working against.

As a user when browsing the customer feature within the application I expect to see a list of customers, each customer will contain the following information:

Customer name

Account number

Account Manager

City

Country

Where to start

ASP.NET MVC is focused around controllers and actions. So its a natural place to start describing how you implement this architecture. On a day to day basic, I write tests first that drive out the behaviour. As my application grows, my layers become cemented. The name of classes denote the responsibility and context.

Creating the Project

I am starting with a new “Asp.Net MVC web application” project called “Web” and a test project called “Web.Specs”. My references are:

This test has driven out the “CustomerController”, an interface called “ICustomerAgent” and two objects called “Customer” and “CustomerListViewModel”.

I have created another class library called “Web.PresentationProcesses” which doesn’t have any additional references. I have placed the Customer, CustomerListViewModel and the ICustomerAgent interface under a new folder called “Customers” in the Web.PresentationProcesses assembly.

The next stage is to have an IOC container resolve the dependencies for as at runtime.

Implementing Inversion of Control

Inversion of control / dependency injection has become very popular over the last couple of years and is a great practice to use. Their are a quite a few containers on the market at the moment, all are very good and apart from the common functionality that they all share. Some of the containers have unique qualities. I have mainly use Castle Windsor, Unity and Ninject. My personal favourite is Ninject because it has a simple fluent interface and contextual binding. At work we are using Unity mainly because its from Microsoft, but we do have applications that use Castle Windsor and Spring.net. I find that once you know one container its really ease to use another. Some of my fellow developers and I do experiment with different containers, although it doesn’t take long to swop them, using the Common Service Locator will make thing easier.

But before i start registering types, I common anti pattern that i have seen is that the container is defined in the web application being at the top of layer stack and then references all of the layers below it so it can add the types to the container. The solution to this is to pass via interface the container reference to each layer and allow a each layer to register its types.

Starting from the top in the web application, new up the container and register the types that are in the web application only like the controllers.

Then from the web application, pass the container reference to the PresentationProcesses layer via an interface. The PresentationProcesses assembly will expose a module object that accepts the container reference.

The module in the PresentationProcesses layer will register its types and then could pass the container reference to the layer below it. If you are using WCF services to expose your service layer then the chain stops here. If your application doesn’t have external services and runs in-process then this pattern continues going down the layer stack.

Some IOC containers allow you to register types in config, code or both. Although i don’t like config anyway, using config to register types can cause problems. Typically when you are refactoring code, like renaming or moving types into other namespaces, that you miss out changing the config files. This results in exceptions at runtime.

I am going to stick with using Unity here and I am going to reference the unity assemblies and use MVCContrib unity assembly:

Microsoft.Practices.Unity.dll

Microsoft.Practices.ObjectBuilder2.dll

MvcContrib.Unity.dll

The best place to get the container created and configured is from within Application object in the Global.asax. If you have used MonoRail and Castle Windsor together then this has the same usage pattern.

Creating the Agent

The next step to create a concrete class that implements the ICustomerAgent interface called “CustomerAgent”. We didn’t need to make it do any at the moment as we are still trying to get the application working at runtime. Plus when we do start making the “CustomerAgent” do something we will drive it from a test first. We will create this class next to where the interface lives.

Now to run the app, and now when you click the “list” link on the home page, you should get an “The method or operation is not implemented.” exception page, which is expected at this time. What this does prove it that the IoC is working correctly.

The next stage in this process would be drive out getting some real data from somewhere and will get returned from the CustomerAgent. Which is going to be in my follow on post, but for now we can simply new up a collection with some new’d up customer objects as shown below.

Run the app

Now when you run the application, click on the “list” link in the menu. You should now get this following page.

Moving on

What we have got is an ASP.NET MVC that has unity in place to resolve types at runtime. We have types (customer and customer ViewModel) defined in the presentation processes layer that the view are bound to. The customer agent returns instances of these types.

The next steps will be to change the Customer agent to get the data from somewhere. This will be driven out via tests. This is going to be the focus on my next post.