Welcome to EMC Consulting Blogs Sign in | Join | Help

Matt Hall's Blog

Experiences with Microsoft technologies

ASP.NET MVC with Castle Windsor

I have been working with ASP.NET MVC over the last few days and wanted to implement dependency injection utilising Castle Windsor. I spent a while nosing around the web for some articles on this and although I found a few there wasn’t anything definitive. So once I had a working version of this on my development VM I thought I would write this post to record my findings.

Firstly, we need to hook into the Application_Start within Global.asax. In here we want to use the ControllerBuilder SetControllerFactory method to specify our own ControllerFactory that will encapsulate our Inversion of Control container of choice, in our case Castle Windsor.

/// <summary>

/// Application on start.

/// </summary>

protected void Application_Start()

{

   RegisterRoutes(RouteTable.Routes);     

   ControllerBuilder.Current.SetControllerFactory(typeof(ControllerFactory));

}

Our custom ControllerFactory class is then defined like so

public class ControllerFactory : IControllerFactory

{

   private readonly WindsorContainer container = new WindsorContainer(HttpContext.Current.Server.MapPath("~/Windsor.config"));

 

   public IController CreateController(RequestContext requestContext, string controllerName)

   {

      return (IController)container.Resolve(controllerName);

   }

 

   public void ReleaseController(IController controller)

   {

      container.Release(controller);

   }

}

We have implemented our own version of the CreateController and ReleaseController methods. In the CreateController method we use the WindsorContainer to obtain the class to be used. This piece of logic is achieved through Convention over Configuration, with the controller name specified being the name of the controller without the Controller suffix. So for example the HomeController class would have the name “Home” and the AccountController class would have the name “Account”.

We then also explicitly release the controller in Castle Windsor to make sure there are no leaks.

The config below gives and example of the windsor config

<configuration>

  <components>

 

    <component

        id="Account"

        type="MVCDemo.Controllers.AccountController, MVCDemo"

        lifestyle="transient"/>

   

    <component

        id="Home"

        type=" MVCDemo.Controllers.HomeController, MVCDemo"

        lifestyle="transient">

 

      <parameters>

        <TestGateway>${testGateway}</TestGateway>

      </parameters>

     

    </component>

 

 

    <component

      id="testGateway"

      service=" MVCDemo.Gateways.IGateway, MVCDemo"

      type=" MVCDemo.Gateways.TestGateway, MVCDemo"

      lifestyle="transient">

    </component>

   

  </components>

 

</configuration>

In the configuration above we are defining two Controllers; the HomeController and the AccountController using the identifiers mentioned previously. These specify the concrete classes to be used.

Additionally, we are specifying that the HomeController has a dependency on the TestGateway class, which implements the IGateway interface. This is all purely for example, but this dependency could be switched easily at a later date to another class that implements the IGateway interface by simply updating this configuration file. I won’t show the definition for the TestGateway class or IGateway interface, as it is irrelevant for this example.

Finally, a modification is required to the HomeController so that the constructor accepts the dependency we have identified.

public HomeController(IGateway gateway)

Now, spinning up the application means the Account and Home controllers being used are those specified in our Windsor configuration file and we are also passing in the TestGateway to the Home controller. On top of this, we can also test the HomeController more effectively by mocking out the IGateway interface using something like Rhino Mocks.

Published 25 March 2009 17:19 by Matthew.Hall
Filed under: , ,

Comments

 

Mike Chaliy said:

This is no reason to have static field container .

ControllerBuilder.Current.SetControllerFactory(typeof(ControllerFactory));

Already act as singleton.

Also you can look at MvcContrib project it already has factories for couple of IoC containers.

March 25, 2009 20:06
 

Matthew.Hall said:

Yes, slight typo there thanks.

With regard to MvcContrib, I had a quick look at that but didn't require everything else that came with it. In addition, I wanted to get this all hooked in by myself.

March 26, 2009 09:05
 

fir3pho3nixx said:

Matthew, I love castle windsor and think it is great that not only Hammet blogs about his creation. You dont necessarily have to explicity define your parameters for your components, the container we have resolves them automatically based on the parameter type through reflection. You can also easily create interceptor by implementing Castle.Core.Interceptor.IInterceptor and putting the following config in ...

<!-- * Service Interceptors * -->

   <component id="applicationServiceInterceptor"

              type="MyApp.Domain.Services.Interceptors.ApplicationServiceInterceptor, MyApp.Domain"

              service="MyApp.Domain.Services.Interceptors.ApplicationServiceInterceptor, MyApp.Domain" />

   <!-- * Main Application Service * -->

   <component id="applicationService"

              lifestyle="transient"

              type="MyApp.ApplicationService, MyApp.Domain"

              service="MyApp.Domain.Services.Interfaces.IApplicationService, MyApp.Domain">

     <interceptors>

       <interceptor>${applicationServiceInterceptor}</interceptor>

     </interceptors>

   </component>

It also works well for separating your concerns to do when Unit testing with Rhino Mocks .... :)

April 9, 2009 10:21
 

Will said:

if you're looking into dependancy injection then you may be interested in StructureMap 2.0...

April 17, 2009 07:07
 

TrackBack said:

September 17, 2009 11:44
New Comments to this post are disabled
Powered by Community Server (Personal Edition), by Telligent Systems