views:

609

answers:

2

Is is possible to inject IPrincipal using Castle Windsor into my asp.net mvc controller. This article by Scott Hanselman has code in the comments to do it with structure map, but I cannot figure out how to do it with Castle.

Update:

Here is what I ended up with for my controller factory. Note that most of the code is from Steve Sanderson's Pro ASP.NET MVC book with the addition of the code from the answers below.

public class WindsorControllerFactory : DefaultControllerFactory
{
    readonly WindsorContainer _container;
    // The constructor:
    // 1. Sets up a new IoC container
    // 2. Registers all components specified in web.config
    // 3. Registers IPrincipal
    // 4. Registers all controller types as components
    public WindsorControllerFactory()
    {
        // Instantiate a container, taking configuration from web.config
        _container = new WindsorContainer(
        new XmlInterpreter(new ConfigResource("castle"))
        );

        _container.AddFacility<FactorySupportFacility>();
        _container.Register(Component.For<IPrincipal>()
          .LifeStyle.PerWebRequest
          .UsingFactoryMethod(() => HttpContext.Current.User));

        // Also register all the controller types as transient
        var controllerTypes = from t in Assembly.GetExecutingAssembly().GetTypes()
                              where typeof(IController).IsAssignableFrom(t)
                              select t;

        foreach (var t in controllerTypes)
            _container.AddComponentLifeStyle(t.FullName, t, LifestyleType.Transient);
    }

    // Constructs the controller instance needed to service each request
    protected override IController GetControllerInstance(Type controllerType)
    {
        return (IController)_container.Resolve(controllerType);
    }        
}
+2  A: 

You try to let Windsor construct your IPrincipal where it has to just use the one that's there. Inject it into the container through the AddComponentInstance method exposed by the MicroKernel in your ControllerFactory.

This would obviously require a custom ControllerFactory, but you should have that already.

I did something similar for HttpContext some time ago: http://www.tigraine.at/2009/01/21/aspnet-mvc-hide-the-httpcontext-services-with-windsor-and-a-custom-controllerfactory/comment-page-1/#comment-2645

Your controller factory could look like this:

public IController CreateController(RequestContext requestContext, string controllerName)  
{  
    container.Kernel.AddComponentInstance<IPrincipal>(typeof (IPrincipal),  
                                                           System.Web.HttpContext.Current.User);  
    return (IController) container.Resolve(controllerName);  
}

(Don't forget that your controllers have to be per-web-request or transient for this or you'll get in trouble)

Tigraine
+6  A: 

If you're using Windsor 2.0, there's no need to modify the ControllerFactory:

var container = new WindsorContainer();
container.AddFacility<FactorySupportFacility>();
container.Register(Component.For<IPrincipal>()
  .LifeStyle.PerWebRequest
  .UsingFactoryMethod(() => HttpContext.Current.User));
// your component registrations...

This is just a wrapper around the Factory facility configuration. If you're using a previous version (RC3) you can configure this with XML too.

Mauricio Scheffer
Oh nice. Didn't know that Windsor got support for FactoryMethods.But the asker is obviously using XML configuration, so the AddComponentInstance will work regardless of Version.
Tigraine
Factory support has been there for a long time, way before the fluent config API... I added a link to the relevant docs.
Mauricio Scheffer
Added this to the Windsor FAQ: http://using.castleproject.org/display/IoC/FAQ
Mauricio Scheffer

related questions