In this blog post, I will explain how to inject your dependencies into your controllers in an MVC 3 application with Castle Windsor.
First of all, you need to create a WindsorInstaller
. This class is responsible for the configuration of your IoC container.
using System.Web.Mvc;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
using Website.Services;
using Website.Controllers;
using Website.Repositories;
namespace Website.Infrastructure
{
public class WindsorInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(FindControllers().Configure
(c => c.LifeStyle.Transient));
container.Register(Component.For<IProductRepository>().ImplementedBy
<ProductRepository>().LifeStyle.Transient);
container.Register(Component.For<ICustomerRepository>().ImplementedBy
<CustomerRepository>().LifeStyle.Transient);
container.Register(Component.For<ISomeWebService>().ImplementedBy
<SomeWebServiceClient>().LifeStyle.Transient);
}
private BasedOnDescriptor FindControllers()
{
return AllTypes.FromThisAssembly()
.BasedOn<IController>()
.If(Component.IsInSameNamespaceAs<HomeController>())
.If(t => t.Name.EndsWith("Controller"));
}
}
}
In the above class, the first line registers all your controllers with lifestyle configured to Transient
. Depending on the lifestyle you choose, Windsor will clean all resources. Other lifestyles are Singleton
, Pooled
, PerWebRequest
, PerThread
. That’s why it is strongly recommended to implement IDisposable
on your classes so Windsor can handle all your resources automatically.
You also need to implement a WindsorControllerFactory
. This will attach the System.Web.Mvc.DefaultControllerFactory
to Windsor
.
using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Castle.MicroKernel;
namespace Website.Infrastructure
{
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel kernel;
public WindsorControllerFactory(IKernel kernel)
{
this.kernel = kernel;
}
public override void ReleaseController(IController controller)
{
kernel.ReleaseComponent(controller);
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, string.Format
("The controller for path '{0}' could not be found.",
requestContext.HttpContext.Request.Path));
}
return (IController)kernel.Resolve(controllerType);
}
}
}
Last but not the least, you have to bootstrap your container. This is done in your Application_Start()
method in the global.asax file.
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Castle.Windsor;
using Castle.Windsor.Installer;
using Website.Infrastructure;
namespace Website
{
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home",
action = "Index", id = UrlParameter.Optional }
);
}
private void BootstrapContainer()
{
Container = new WindsorContainer()
.Install(FromAssembly.This());
var controllerFactory = new WindsorControllerFactory(Container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
}
public IWindsorContainer Container { get; private set; }
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
BootstrapContainer();
}
}
}
With these things setup, all the dependencies you registered in your WindsorInstaller
will be automatically injected to your controllers. Below, I have added an example controller implementation to show you how to use the dependencyInjection
.
using System;
using System.Linq;
using System.Web.Mvc;
using Website.Repositories;
namespace Website.Controllers
{
public class ProductController : Controller
{
private readonly IProductRepository _repository;
public ProductController(IProductRepository repository)
{
_repository = repository;
}
public ActionResult Index()
{
var products = _repository.All();
return View(products);
}
public ActionResult Details(int id)
{
var product = _repository.GetById(id);
return View(product);
}
}
}
To keep track of your resources, you should implement IDisposable
on your repositories so resources will be released automatically. In the example, I use Entity Framework Code First. Because I implemented the Dispose
method, also my connection to my database will be released without the need to think about it everywhere in my code.
using System;
using System.Linq;
using Website.Infrastructure;
using Website.Models;
namespace Website.Repositories
{
public class ProductRepository : IProductRepository, IDisposable
{
private WebsiteReadModelContext _context = new WebsiteReadModelContext();
public IEnumerable<Product> All()
{
_context.Products.Select();
}
public Product GetById(int Id)
{
_context.Products.SingleOrDefault(p => p.Id == id);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_context != null)
{
_context.Dispose();
_context = null;
}
}
}
}
}
I hope you found this blog post usable.
CodeProject
I am a .NET Software Developer at Atos International. Architecture, CQRS, DDD, C#, ASP.NET, MVC3, HTML5, Jquery, WP7, WPF, ncqrs, Node.js