由于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;
}
答案 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实现(以及其他一些东西)。我建议分配存储库并实现缺少的扩展点(不应该太难),然后向团队发送拉取请求。