Castle Windsor依赖Resolver for MVC 3

时间:2010-11-10 03:02:57

标签: asp.net-mvc asp.net-mvc-3 castle-windsor

由于MVC 3中的IoC / DI实现很可能是RC中的最终形式,我正在寻找使用Caste Windsor的DependencyResolver,IControllerActivator和IViewPageActivator的更新实现。有没有为MVC 3 RC更新过的例子?

编辑#1 实现Windsor依赖解析器确实是微不足道的,但仍然缺少一些东西。与Jeff Putz的Ninject示例(下图)相反,它似乎并不像Windsor那么简单。设置依赖性解析器之后,

DependencyResolver.SetResolver(new WindsorDependencyResolver(container)); 

Windsor抛出ComponentNotFoundException。我需要为IControllerFactory和IControllerActivator提供实现。由于DefaultControllerFactory可以识别DependencyResolver,因此可以按如下方式解决:

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

WindsorControllerActivator也是微不足道的。但是,这会导致IViewPageActivator的另一个ComponentNotFoundException。

这让我相信我错过了什么。没有办法比实现一个控制器工厂和调用ControllerBuilder.Current.SetControllerFactory MVC 2.0风格更复杂。

编辑#2 我错过了在无法找到服务时Dependency解析器需要返回null的微妙但重要的细节。实施如下:

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[]{};
    }
}

编辑#3

回复评论中的问题。如果你确实发现你需要自己的IControllerActivator,这里有一个简单的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);
    }
}

}

同样,基本DI使用Windsor和MVC3依赖性解析器需要 NOT

编辑#4 基于一些进一步的研究和反馈,似乎传统的控制器工厂实施是Windsor和MVC3的最佳方法。令人担忧的是IDependencyResolver接口缺少一个释放方法,这可能导致内存泄漏,Windsor不会丢弃其组件。如果使用PerWebRequest生命周期解决所有依赖关系,这可能不会成为问题,但最好不要抓住机会。这是MVC3的Windsor控制器工厂的基本实现。

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);
    }
}

编辑#5 如果您正在使用MVC区域,则上述实现将不适合您。您需要根据其全名注册每个控制器,并重写GetControllerInstance而不是CreateController:

 protected override IController GetControllerInstance(RequestContext context, Type controllerType)
    {
        if (controllerType != null)
        {
            return (IController)container.Kernel.Resolve(controllerType);
        }
        return null;
    }

3 个答案:

答案 0 :(得分:24)

MVC3 IDependencyResolver接口有一个很大的问题:没有发布方法。这意味着如果要将其与Windsor一起使用,可能存在内存泄漏。请在此处查看我的博客文章:

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

答案 1 :(得分:10)

自测试版发布以来,界面没有发生变化,因此各种框架的所有实现都应该可行。事实是,界面并不复杂......你应该能够毫不费力地自己动手。例如,我为Ninject做了这个:

public class NinjectDependencyResolver : IDependencyResolver
{
    public NinjectDependencyResolver(IKernel kernel)
    {
        _kernel = kernel;
    }

    private readonly IKernel _kernel;

    public object GetService(Type serviceType)
    {
        return _kernel.TryGet(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return _kernel.GetAll(serviceType);
    }
}

然后将其连接到global.asax,如下所示:

    private static IKernel _kernel;
    public IKernel Kernel
    {
        get { return _kernel; }
    }

    public void Application_Start()
    {
        _kernel = new StandardKernel(new CoreInjectionModule());
        DependencyResolver.SetResolver(new NinjectDependencyResolver(Kernel));
        ...
    }

请记住,此时您可以免费获得各种好东西,包括DI控制器,控制器工厂,动作过滤器和视图基类。

编辑:要明确,我不确定你的“激活者”是什么,但你可能不需要它们。 IDependencyResolver接口自动处理控制器和视图的新增功能。

答案 2 :(得分:2)

MVCContrib目前是IoC-MVC集成的权威来源。目前,MVC3分支仅包括控制器工厂和IDependencyResolver实现(以及其他一些东西)。我建议分配存储库并实现缺少的扩展点(不应该太难),然后向团队发送拉取请求。