DependencyResolver.SetResolver(new WindsorDependencyResolver(container));
Windsor抛出了ComponentNotFoundException异常。我需要提供IControllerFactory和IControllerActivator的实现。由于DefaultControllerFactory支持DependencyResolver,可以按以下方式解决此问题:
Component.For<IControllerFactory >().ImplementedBy<DefaultControllerFactory>()
Component.For<IControllerActivator >().ImplementedBy<WindsorControllerActivator>(),
WindsorControllerActivator非常简单。然而,这会导致另一个IViewPageActivator的ComponentNotFoundException。
这使我相信我漏掉了一些东西。这不可能比实现控制器工厂并以MVC 2.0方式调用ControllerBuilder.Current.SetControllerFactory更复杂。
编辑#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[]{};
}
}
第三次编辑
回答评论区中的一个问题。如果你确实需要自己的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);
}
}
}
再次强调,使用Windsor和MVC3的依赖解析器实现基本DI不需要此操作。
编辑 #4 根据一些进一步的研究和反馈,传统控制器工厂实现似乎是Windsor和MVC3的最佳方法。问题在于IDependencyResolver接口缺少一个release方法,这可能会导致Windsor不释放其组件而导致内存泄漏。如果所有的依赖都使用PerWebRequest 生命周期进行解析,则这可能不是问题,但最好不要冒险。这里是一个基本的Windsor控制器工厂实现示例用于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);
}
}
编辑 #5 如果你正在使用MVC区域,上述实现将无法正常工作。你需要根据每个控制器的完整名称注册它们,并重写GetControllerInstance而不是CreateController:
protected override IController GetControllerInstance(RequestContext context, Type controllerType)
{
if (controllerType != null)
{
return (IController)container.Kernel.Resolve(controllerType);
}
return null;
}