There are contrary signals on the web regarding Window DI and the new-ish MVC-ish WebApi IDependencyResolver
. Fortunately, by late 2012 Mark Seemann summarised the state-of-the-art: don't use it.
- http://blog.ploeh.dk/2012/10/02/DependencyInjectioninASP.NETWebAPIwithCastleWindsor/
- http://blog.ploeh.dk/2012/09/27/DependencyInjectionandLifetimeManagementwithASP.NETWebAPI/
The reason: it doesn't allow your DI container to properly manage lifetimes. Instead, do this:
public class WindsorCompositionRoot : IHttpControllerActivator { private readonly IWindsorContainer container; public WindsorCompositionRoot(IWindsorContainer container) { this.container = container; } public IHttpController Create( HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType) { var controller = (IHttpController)this.container.Resolve(controllerType); request.RegisterForDispose( new Release( () => this.container.Release(controller))); return controller; } private class Release : IDisposable { private readonly Action release; public Release(Action release) { this.release = release; } public void Dispose() { this.release(); } } }
and wire it up with this line during Application_Start
in Global.asax.cs
GlobalConfiguration.Configuration.Services.Replace( typeof(IHttpControllerActivator), new WindsorCompositionRoot());
Using Windsor for plain old MVC html pages inside WebApi projects
if you are using MVC
controllers with views for html pages as well as IHttpControllers
in your WebApi
project, then you need to know that the WebApi
controllers & activation is a quite separate subsystem from the MVC
controllers. You still need the usual WindsorControllerFactory
to hook Windsor into the MVC
pages as well as the above for the WebApi
controllers.
Code for a WindsorControllerFactory
can be found in a couple of places, but this is from the Castle Windsor tutorial for Asp.Net 3 and is still valid for Asp.Net 4:
using System; using System.Web; using System.Web.Mvc; using System.Web.Routing; using Castle.MicroKernel; 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); } }
and again, you must hook it into the application object in Global.asax.cs
private static IWindsorContainer container; //These lines should be called during Application_Start container = new WindsorContainer().Install(FromAssembly.This()); var controllerFactory = new WindsorControllerFactory(container.Kernel); ControllerBuilder.Current.SetControllerFactory(controllerFactory); // And this in Application_End: container.Dispose();