2011-09-27 23 views
1

目前我已经有了一个相当复杂的项目,并且作为其中的一部分,我有一个纯粹处理插件加载的MEF层,然后新加载的插件公开其使用asp.mvc及其注册的路线控制器添加到Ninject的绑定。Ninject.Web.Mvc知道动态加载控制器,但ASP.Mvc does not?

然而,即使为路由中的插件正确添加了命名空间,当动态添加的路由被命中(并且它们被命中,我已经检查过路由调试器)时,问题就出现了。当我说我已经添加了命名空间我的意思是像如下:

var namespaces = new [] { "MyPlugin.Controllers" }; 
routeCollection.MapRoute(
        PluginRoute, "plugin/{action}", 
        new { controller = "Plugin", action = "Default" }, 
        namespaces); 

只给多一点背景下这种情况下,我从NinjectHttpApplication继承,而不是做其他事情,没有自定义控制器工厂,没有自定义的依赖解析器,就是Ninject给我的。然后我把当前活动的内核,给它的插件,他们自己注册。

现在被击中的路线不起作用,即使他们被击中并且控制器被注册到Ninject内核,也只是得到了404的任何外部路由。所以我想,虽然Ninject有注册的类型,MVC的DefaultControllerFactory不能调用通过时找到类型:

GetControllerTypeWithinNamespaces(string controllerName, HashSet<string> namespaces) 

一件事,令我感到困惑的时刻,虽然,是它不与发现它甚至正确的命名空间......但是,只是为了证明我的假设,如果我在asp mvc项目中添加插件作为参考并运行它(不更改任何代码,只是插件程序集是项目中的参考,所以它最终会在bin目录中)它将工作。命中路线,我得到所需的输出...

所以在这一点上,我想知道,如果虽然MEF托管外部DLL,它不是以某种方式与当前的AppDomain共享它...什么似乎很奇怪......

这是我目前的阻挡者,所以任何建议都会很棒!

+0

你可以尝试使用依赖解析器吗? –

+0

这些插件在全部故障时位于哪里?你有没有试过将它们复制到你正在运行的项目的'bin'文件夹中? – Jeroen

+0

我不得不硬着头皮写一些代码来观察插件文件夹,并且每当有更改将其移入bin目录时。我很想实现另一个解决方案,但我不认为其中一个存在,除了获取程序集并将它们手动加载到AppDomain中,但不能在不卸载整个AppDomain的情况下从中删除它们,并且如果您开始获取多个他们,它会变得混乱... – Grofit

回答

2

看来DefaultControllerFactory不知道哪种是负责处理请求。你要么找出为什么DefaultControllerFactory不知道这些控制器,要么提供你自己的实现来处理这些情况。问题肯定比Ninject相关的MEF更多。

public class MyControllerFactory : DefaultControllerFactory 
{ 
    public override IController CreateController(RequestContext requestContext, string controllerName) 
    { 
     Type controllerType = this.GetControllerType(requestContext, controllerName) ?? this.GetPluginControllerType(requestContext, controllerName) 

     return this.GetControllerInstance(requestContext, controllerType); 
    } 

    private Type GetPluginControllerType(RequestContext requestContext, string controllerName) 
    { 
     // put your own implementation here 
    } 
} 

另一种解决方案是使用Ninject'ss组件装载机构代替MEF。

+0

我不知道Ninject甚至有这样的机制,如果是这样的话,我宁愿使用它,而不是将新技术添加到堆栈中,是扩展还是只是一种模式?您可以在该功能上提供的任何信息都会很棒!我仍然觉得奇怪的是,DefaultControllerFactory无法找到类型...作为它在同一AppDomain中(据我所知)和类型IS注册... – Grofit

+0

其中一个kernel.Load重载需要一个路径来扫描包含程序集NinjectModule定义。 –

+0

嗯,我对你很不幸,我不认为这会解决我*真实*问题。理想情况下,我需要能够将几个接口实例动态加载到列表中。即IList 插件{get; set;}。目前所有我使用MEF的,所以每个插件在运行时加载到这个列表中,其他人也可以添加。然而,根据你的建议,我认为它只是一种动态获取绑定的方式,我不认为会满足这个要求,因为它只会将列表绑定到1个实例,而不是像MEF那样用多个实例来填充它。 – Grofit

0

听起来和mef有关,当你尝试直接从内核实例化类时会发生什么?如果一切正常,你可以只创建自己的控制器工厂:

public class NinjectControllerFactory : DefaultControllerFactory 
{ 
    private IKernel _kernel; 

    public NinjectControllerFactory(IKernel kernel) 
    { 
     _kernel = kernel; 
    } 

    protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType) 
    { 
     if (controllerType == null) 
      return null; 

     return (IController)_kernel.Get(controllerType); 
    } 
} 

虽然这些天MVC 3,我不与理会的ControllerFactory和依赖解析器水平犹豫。

public class NinjectDependencyResolver : IDependencyResolver 
{ 
    private IKernel _kernel; 

    public NinjectDependencyResolver(IKernel kernel) 
    { 
     _kernel = kernel; 
    } 

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

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

n.b.都需要在的Application_Start分别临时用户(虽然你只使用一个)

ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory(_kernel)); 

DependencyResolver.SetResolver(new NinjectDependencyResolver(_kernel));