编辑#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
我错过了微妙但重要的细节,当无法找到服务时,依赖解析程序需要返回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依赖解析器。
编辑#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; }
解决方法
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接口自动处理控制器和视图的新建。