MVC#

Setting Up IoC in ASP.NET MVC using Castle Windsor

Posted in ASP.NET MVC, Controllers, IoC by BlueCoder on 09/01/2010

Abstract: This post gathers information needed to setting up Inversion of Control (IoC) in an ASP.NET MVC application using Castle Windsor.

Introduction: In previous post I summarized how ASP.NET MVC components work together to process request from user and return result . In that post I mentioned we can customize each step to satisfy our needs so I’m going to show you how you can create a custom Controller Factory to implement IoC in your application. For more information about IoC and why we use it you can take a look at this like :http://www.mikesdotnetting.com/Article/117/Dependency-Injection-and-Inversion-of-Control-with-ASP.NET-MVC .

I learned how to use Windsor to set up IoC by reading the great book of Steven Sanderson “Pro ASP.NET MVC framework”. You can read the section I used for this post here :Pro ASP.NET MVC framework by Steven Sanderson

You can get the latest version of Castle project here : www.castleproject.org/castle/download.html

After download and install Castle Project follow these steps to set up IoC in a very simple MVC project. I use default project template & routing configuration that comes with MVC 2.

1.Right click your References folder and add reference to “Castle.Core.dll”, “Castle.MicroKernel.dll”, “Castle.Windsor.dll” files which are in  “C:\Program Files\CastleProject\Bin\net-2.0 after installing Castle.

Add Reference to Castle

2.Next we are going to create a custom Controller Factory class. Add WindsorControllerFactory.cs to the root of your application and write these lines of codes to create a controller factory which uses castle to load the required objects at run time base on configuration section which we set up later. Don’t afraid of XML & Reflection parts in the code. These snippets just say to Windsor Container that where in the Web.config file look for registering components and Reflection part just registers all controllers’ types as components. Usually when we use IoC we want to inject an object to an constructor parameter at run time, but in constructor code we just say which interface that object implements but IoC Container loads the needed object base on its configuration. The Interfaces, objects and classes which their constructor injected are components of an IoC container. In this example we register components in two places: We register controllers in the controller factory but register other types using  castle section in Web.config file. So let just right the needed Controller Factory which uses the snippets of Steven’s book that I just updated it to be compatible with MVC 2:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Castle.Windsor;
using Castle.Windsor.Configuration.Interpreters;
using Castle.Core.Resource;
using System.Reflection;
using Castle.Core;
using System.Web.Routing;

namespace Mvc2Application6
{
    public class WindsorControllerFactory : DefaultControllerFactory
    {
        WindsorContainer container;
        // The constructor:
        // 1. Sets up a new IoC container
        // 2. Registers all components specified in web.config
        // 3. Registers all controller types as components
        public WindsorControllerFactory()
        {
            // Instantiate a container, taking configuration from web.config
            container = new WindsorContainer(
            new XmlInterpreter(new ConfigResource("castle"))
            );
            // Also register all the controller types as transient
            var controllerTypes =
                from t in Assembly.GetExecutingAssembly().GetTypes()
                                  where typeof(IController).IsAssignableFrom(t)
                                  select t;
            foreach (Type t in controllerTypes)
                container.AddComponentWithLifestyle
                    (t.FullName, t,LifestyleType.Transient);
        }

        // Constructs the controller instance needed to service each request this part is Updated to be compatible with MVC 2
        protected override IController
            GetControllerInstance
            (RequestContext requestContext, Type controllerType)
        {
            return (IController)container.Resolve(controllerType);
        }
        /*
         * For MVC 1 use this
        protected override IController GetControllerInstance(Type controllerType)
        {
            return (IController)container.Resolve(controllerType);
        }*/
    }
}

Note : This post works with Castle 1 RC 3. I recently got an email from one of readers that this not works with the latest version which is 2
so for those folks who want to work which the latest version I notify that instead of AddComponentWithLifestyle method they should use the new AddComponentLifeStyle method.

3.To ASP.NET MVC use your new controller factory add this to the application start method of your global.asax.cs file :

ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory());

4. Next we need manipulate our Web.config file in the root of the application: Add a <castle> node directly in the configuration node: <castle><components></components></castle> we edit this shortly. In the configSections node add this:

<section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler,Castle.Windsor" />

5. To work with our new IoC structure you need to construct your application to use it so follow these steps to set up a simple application which use our IoC implementation:
Create an IEbookRepository interface in Model folder:

namespace Mvc2Application6.Models

{

public interface IEbookRepository

{

IEnumerable<Book> ListEbook();

}

}

As you see it’s a simple interface with a property that returns a list of Books. Book is a simple class with 3 properties:

namespace Mvc2Application6.Models

{

public class Book

{

public int ID { get; set; }

public string Name { get; set; }

public string Author { get; set; }

}

}

Create a concrete class which implements IEbookRepository interface (for simplicity we don’t touch DB and an in memory  list of books satisfies our example):


namespace Mvc2Application6.Models

{

public class EBookRepository : IEbookRepository

{

public IEnumerable<Book> ListEbook()

{

List<Book> books = new List<Book>();

books.Add(new Book { ID = 1, Author = "Steven Sanderson", Name = "Pro ASP.NET MVC framewok" });

books.Add(new Book { ID = 2, Author = "Stphan Waler", Name = "ASP.NET MVC framework Unleashed" });

books.Add(new Book { ID = 3, Author = "Scott Guthrie", Name = "ASP.NET MVC 1.0" });

return books;

}

}

}

Add a new Constructor to your Home Controller:

private IEbookRepository _repository ;

public HomeController(IEbookRepository repository)

{

this._repository = repository;

}

Now we need to tell WindsorContainer to inject IEbookRepository with an object of type EBookRepository so back to your Web.config file and edit castle node we created in step 4:


<castle>

<components>

<component id="EbookRepository"

service="Mvc2Application6.Models.IEbookRepository,Mvc2Application6"

type="Mvc2Application6.Models.EBookRepository,Mvc2Application6"

lifestyle="PerWebRequest">

</component>

</components>

</castle>

This says whenever a class has a dependency to a IEbookRepository (in our example through its constructor) IoC container should load an EBookRepository  object with whenever a web  request comes.

Then we need to register Windsor’s PerRequestLifestyle module in httpModules section :

<add name="PerRequestLifestyle" type="Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule,Castle.MicroKernel" />

To register Windsor’s PerRequestLifestyle for IIS 7 refer to the original book “APRESS Pro ASP.NET MVC framework” or use the Google book link above.

So that’s it we set up an IoC container for our ASP.NET MVC application.

you can download sample project here.

Summary: We used Castle Windsor to Set up IoC in a very simple MVC application and for this we created a custom controller factory and added some configuration in web.config file. We also edited Application Start Method to tell MVC use our new controller factory instead of DefaultControllerFactory.


Shout it

kick it on DotNetKicks.com

About these ads

37 Responses

Subscribe to comments with RSS.

  1. DotNetShoutout said, on 09/01/2010 at 13:28

    Setting Up IoC in ASP.NET MVC using Castle Windsor « MVC#…

    Thank you for submitting this cool story – Trackback from DotNetShoutout…

  2. progg.ru said, on 09/01/2010 at 15:39

    Установка контейнера IoC в ASP.NET MVC используя Castle Windsor…

    Thank you for submitting this cool story – Trackback from progg.ru…

  3. Panus said, on 09/01/2010 at 19:48

    The best blog thanks.

  4. [...] to VoteSetting Up IoC in ASP.NET MVC using Castle Windsor « MVC# (1/9/2010)Saturday, January 09, 2010 from ali62bIntroduction: In previous post I summarized how ASP.NET MVC [...]

  5. Steve Maher said, on 26/01/2010 at 07:26

    To date, Sanderson’s book is the most useful published work I’ve seen. Although it is now dated (MVC 1.0), it is a great reference with a number of useful tips.

  6. [...] hit the front page of ASP.NET site By blueconcept Today my new post on http://mvcsharp.wordpress.com “Setting Up IoC in ASP.NET MVC using Castle Windsor” [...]

  7. Pavel said, on 26/01/2010 at 15:30

    Thank’s for article. Is there some way to make model binder factory like controller factory to inject constructor parameters in custom model binders?

  8. [...] Setting Up IoC in ASP.NET MVC using Castle Windsor (Ali Bastani) [...]

  9. ASP.NET MVC Archived Buzz, Page 1 said, on 27/01/2010 at 02:02

    [...] to Vote[FriendFeed] Setting Up IoC in ASP.NET MVC using Castle Windsor « MVC# (1/26/2010)Tuesday, January 26, 2010 from [...]

  10. http://ignou-student.blogspot.com said, on 27/01/2010 at 08:55

    Thanks,
    Great article, I use it in my coding.

  11. Sean Iannuzzi said, on 27/01/2010 at 18:00

    Interesting Article, but how does this IoC stack up against the other IoC’s that are out there?

    • ali62b said, on 28/01/2010 at 09:57

      I some how didn’t like AutoFac syntax and Ninject that using Attributes but I like simplicity of StructureMap and if the bugs in new version not bother I use it in my next project. So right now Castle is more stable than StructureMap but in future may StructureMap be my choice.

      • Paul Morrison said, on 04/02/2010 at 04:31

        I like the idea of using StructureMap :)

        Hello from France, Paul

  12. teeth whitening said, on 29/01/2010 at 11:11

    Well spoken. I have to research more on this as it is really vital info

  13. Tommy said, on 09/03/2010 at 23:16

    Hello! Great article–I’ve been trying to do this example from the apress book and figured out the change for GetControllerInstance for MVC 2, but I still run into the exception:

    Castle.MicroKernel.Handlers.HandlerException was unhandled by user code
    Message=Can’t create component ‘WebUI.Controllers.ProductsController’ as it has dependencies to be satisfied.
    WebUI.Controllers.ProductsController is waiting for the following dependencies:

    Services:
    – DomainModel.Abstract.IProductsRepository which was not registered.

    Source=Castle.MicroKernel
    StackTrace:
    at Castle.MicroKernel.Handlers.DefaultHandler.AssertNotWaitingForDependency()
    at Castle.MicroKernel.Handlers.DefaultHandler.ResolveCore(CreationContext context, Boolean track)
    at Castle.MicroKernel.Handlers.AbstractHandler.Resolve(CreationContext context)
    at Castle.MicroKernel.DefaultKernel.ResolveComponent(IHandler handler, Type service, IDictionary additionalArguments)
    at Castle.MicroKernel.DefaultKernel.ResolveComponent(IHandler handler, Type service)
    at Castle.MicroKernel.DefaultKernel.get_Item(Type service)
    at Castle.Windsor.WindsorContainer.Resolve(Type service)
    at WindsorControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType) in C:\Users\tommysu\documents\visual studio 2010\Projects\ShoppyTown\WebUI\WindsorControllerFactory.cs:line 36
    at System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName)
    at System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory)
    at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state)
    at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state)
    at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
    at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
    at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
    InnerException:

    Do you have any ideas of what else to check?

    • ali62b said, on 10/03/2010 at 17:51

      You should add

      castle
      properties
      SpostsStoreConnStr
      Data Source=.\sqlexpress2008;Initial Catalog=SportsStore;Persist Security Info=True;User ID=xxxxxx;Password=xxxxx
      SpostsStoreConnStr
      properties
      components

      component id=”ProdsRepository”
      service=”DomainModel.Abstract.IProductsRepository,DomainModel”
      type=”DomainModel.Concrete.SqlProductsRepository,DomainModel”
      lifestyle=”PerWebRequest”
      parameters
      connectionString
      #{SpostsStoreConnStr}
      connectionString
      parameters
      component
      component
      components
      castle

      to your web.config file as mentioned in page 101. Hope this helps.

  14. Mr. D said, on 10/04/2010 at 20:30

    Hi, I’m trying to implement your code and I getting this error on WindsorControllerFactory.cs: ArgumentNullException was unhandled by user code

    I even getting this error on your sample code as well.

    // Constructs the controller instance needed to service each request
    protected override IController
    GetControllerInstance
    (RequestContext requestContext, Type controllerType)
    {
    return (IController)container.Resolve(controllerType); // At the controllerType gives ArgumentNullException.
    }

  15. Bobby said, on 19/04/2010 at 18:32

    Hey there,

    what a great article. Thanks for posting it. I started modifying it to use NHibernate for database and was wondering if you have an example that would help me with setting up NHibernate and windsor.

    thanks

  16. erick said, on 04/05/2010 at 07:05

    still go a problem

    Error 3 ‘WebUI.WindsorControllerFactory.GetControllerInstance(System.Web.Routing.RequestContext, System.Type)': no suitable method found to override C:\Documents and Settings\Administrator\My Documents\Visual Studio 2008\Projects\myMVCProjects\WebUI 2.0\WindsorControllerFactory.cs 36 40 WebUI 2.0

    i’m using castle windsor 2.1 and VS.NET 2008 SP1 and MVC 2.0

    i very new to this one..what’s wrong with it?
    any insight?

  17. erick said, on 04/05/2010 at 07:45

    aarg..silly me…

    it all when wrong if we dont inherits the class from DefaultControllerFactory

    sori for the post..

    thx

  18. Dennis said, on 14/08/2010 at 13:01

    You forgot to implement the release method. Otherwise the controllers will stay in memory.

    public override void ReleaseController(IController controller)
    {
    container.Release(controller);
    }

    • ali62b said, on 14/08/2010 at 17:04

      Thanks for the comment. (I edited your code and changed “_container” to “container”)

    • Herman van der Blom said, on 29/09/2011 at 20:10

      Yes, he did forget that indeed. I just used it blindly in a Production System and then was confronted with a worker process that at some point became 2Gb. So I did found out the hard way :-(

  19. Sung Hun Park said, on 06/11/2010 at 16:18

    Hi.
    I am working with VS2008, MVC2, Castle Windsor 2.5.1

    I have been struggling the following error in the Web.config.

    The error message says that ASP.NET MVC could not load a file or assembly. If you know about this problem, would you please let me know?

  20. Luke said, on 05/02/2011 at 02:01

    Great read, inversion of control is key to apply the fundamentals of SOLID.

  21. Tinto said, on 13/02/2011 at 23:46

    Thanks, your article really helped :D

  22. Nivetha said, on 14/03/2011 at 08:05

    I am very new to the castle framework.Can anyone tell me what are al the applications we can use the castle framework? Is it possible to only in dot net mvc applications?

  23. Danny Acuna said, on 03/05/2011 at 23:04

    I’ve been trying to follow your tutorial but I’m getting stuck in that the new version WindsorContainer does not contain the method AddComponentWithLifestyle. I did some research and came up empty. Any help would be much appreciated.

  24. Przeklady said, on 17/05/2011 at 16:45

    This web site is my intake , real great layout and perfect written content .

  25. eransmith2010 said, on 12/07/2011 at 12:17

    Nice blog. The info you provided id really good and helpful. Thanx

  26. saidahmed said, on 07/09/2011 at 17:33

    At me this error:Parser error message: It is impossible to load a file or assemblage “Castle. MicroKernel” or one of components dependent on them. It is not possible to find the specified file. (C:\My Documents\Visual Studio 2008\Projects\SportStore\WebUi\web.config line 126)
    error:Ошибка источника:

    Строка 124:
    Строка 125:
    Строка 126:

  27. Windsor Serviced Apartments said, on 03/03/2012 at 03:25

    Can I just say what a comfort to find someone that really knows what they’re talking about over the internet. You actually realize how to bring a problem to light and make it important. More people ought to read this and understand this side of the story. I can’t believe you are not more popular because you definitely have the gift.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: