Setting Up IoC in ASP.NET MVC using Castle Windsor
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.
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.
Setting Up IoC in ASP.NET MVC using Castle Windsor « MVC#…
Thank you for submitting this cool story – Trackback from DotNetShoutout…
Установка контейнера IoC в ASP.NET MVC используя Castle Windsor…
Thank you for submitting this cool story – Trackback from progg.ru…
The best blog thanks.
[…] 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 […]
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.
[…] hit the front page of ASP.NET site By blueconcept Today my new post on https://mvcsharp.wordpress.com “Setting Up IoC in ASP.NET MVC using Castle Windsor” […]
Thank’s for article. Is there some way to make model binder factory like controller factory to inject constructor parameters in custom model binders?
[…] Setting Up IoC in ASP.NET MVC using Castle Windsor (Ali Bastani) […]
[…] to Vote[FriendFeed] Setting Up IoC in ASP.NET MVC using Castle Windsor « MVC# (1/26/2010)Tuesday, January 26, 2010 from […]
Thanks,
Great article, I use it in my coding.
Glad to hear that. Happy MVCing.
Interesting Article, but how does this IoC stack up against the other IoC’s that are out there?
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.
I like the idea of using StructureMap 🙂
Hello from France, Paul
Well spoken. I have to research more on this as it is really vital info
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?
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.
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.
}
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
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?
aarg..silly me…
it all when wrong if we dont inherits the class from DefaultControllerFactory
sori for the post..
thx
You forgot to implement the release method. Otherwise the controllers will stay in memory.
public override void ReleaseController(IController controller)
{
container.Release(controller);
}
Thanks for the comment. (I edited your code and changed “_container” to “container”)
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 😦
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?
The error was following line in the Web.config.
I guess you are using
change it to
http://www.dbones.co.uk/blog/post/2010/12/upgrading-windsor-a-small-gotcha
It removed my code….
goto my site see if that was your issue
http://www.dbones.co.uk/blog/post/2010/12/upgrading-windsor-a-small-gotcha
Great read, inversion of control is key to apply the fundamentals of SOLID.
Thanks, your article really helped 😀
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?
Check out this link for more info about the framework and related project:
http://www.castleproject.org/castle/index.html
Hope this helps.
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.
This web site is my intake , real great layout and perfect written content .
Nice blog. The info you provided id really good and helpful. Thanx
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:
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.