Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
396 views
in Technique[技术] by (71.8m points)

asp.net mvc - Castle Windsor Dependency Resolver for MVC 3

Since the IoC/DI implementation in MVC 3 is most likely in its final form in the RC, I'm looking for an updated implementation of the DependencyResolver, IControllerActivator and IViewPageActivator using Caste Windsor. Are there any examples out there that have been updated for MVC 3 RC?

EDIT #1 Implementing a Windsor dependency resolver is indeed trivial, but there's still something missing. Contrary to Jeff Putz's Ninject example (below), it appears that it's not as simple as that with Windsor. After setting the dependency resolver like so,

DependencyResolver.SetResolver(new WindsorDependencyResolver(container)); 

Windsor throws ComponentNotFoundException. I need to provide implementations for IControllerFactory and IControllerActivator. Since the DefaultControllerFactory is DependencyResolver aware, this can be solved as follows:

Component.For<IControllerFactory >().ImplementedBy<DefaultControllerFactory>()
Component.For<IControllerActivator >().ImplementedBy<WindsorControllerActivator>(),

WindsorControllerActivator is trivial as well. However, this leads to another ComponentNotFoundException for IViewPageActivator.

This leads me to believe that I'm missing something. There is no way that this should be more complicated than an implementing a controller factory and calling ControllerBuilder.Current.SetControllerFactory MVC 2.0-style.

EDIT #2 I missed the subtle but important detail that the Dependency resolver needs to return null when a service cannot be found. The implementation is as follows:

public class WindsorDependencyResolver : IDependencyResolver
{
    private readonly IWindsorContainer container;

    public WindsorDependencyResolver(IWindsorContainer container)
    {
        this.container = container;
    }

    public object GetService(Type serviceType)
    {
        return container.Kernel.HasComponent(serviceType) ? container.Resolve(serviceType) : null;
    }

  public IEnumerable<object> GetServices(Type serviceType)
    {
        return container.Kernel.HasComponent(serviceType) ? container.ResolveAll(serviceType).Cast<object>() : new object[]{};
    }
}

EDIT #3

Responding to a question in the comments. If you do find that you need your own IControllerActivator, here a simple implementation for Windsor:

public class WindsorControllerActivator : IControllerActivator
{
    private readonly IWindsorContainer container;

    public WindsorControllerActivator(IWindsorContainer container)
    {
        this.container = container;
    }

    public IController Create(RequestContext requestContext, Type controllerType)
    {
        return (IController)container.GetService(controllerType);
    }
}

}

Again, this is NOT necessary to get basic DI working with Windsor and the MVC3 dependency resolver.

EDIT #4 Based on some further research and feedback, it seems that a traditional controller factory implementation is the best approach for Windsor and MVC3. The concern is that the IDependencyResolver interface lacks a release method, which could cause memory leaks with Windsor not disposing its components. This is probably not going to be an issue if all of your dependencies are resolved with the PerWebRequest lifecycle, but it's still better not to take the chance. Here's a basic implementation of a Windsor controller factory for MVC3.

public class WindsorControllerFactory : DefaultControllerFactory
{
    private readonly IWindsorContainer container;

    public WindsorControllerFactory(IWindsorContainer container)
    {
        this.container = container;
    }

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

    public override IController CreateController(RequestContext requestContext, string controllerName)
    {
        var controllerComponentName = controllerName + "Controller";
        return container.Kernel.Resolve<IController>(controllerComponentName);
    }
}

EDIT #5 If you're using MVC areas, the above implementation will not work for you. You will need to register each controller based on its full name, and override GetControllerInstance instead of CreateController:

 protected override IController GetControllerInstance(RequestContext context, Type controllerType)
    {
        if (controllerType != null)
        {
            return (IController)container.Kernel.Resolve(controllerType);
        }
        return null;
    }
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The MVC3 IDependencyResolver interface has a big problem: no release method. This means that there is a potential memory leak if you are going to use it with Windsor. See my blog post about it here:

http://mikehadlow.blogspot.com/2011/02/mvc-30-idependencyresolver-interface-is.html


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...