我现在有一个非常复杂的项目,作为其中的一部分,我有一个MEF层,它纯粹处理插件的加载,然后新加载的插件暴露他们的路由,这些路由注册了asp.mvc和他们的控制器被添加到Ninject的绑定中。
然而,当动态添加的路由被命中(并且它们被命中,我已经使用路由调试器检查)时,即使为路由中的插件正确添加了命名空间,也会出现问题。当我说我添加了名称空间时,我的意思如下:
var namespaces = new [] { "MyPlugin.Controllers" };
routeCollection.MapRoute(
PluginRoute, "plugin/{action}",
new { controller = "Plugin", action = "Default" },
namespaces);
为了给这种情况提供更多的上下文,我继承了NinjectHttpApplication而没有做任何事情,没有自定义控制器工厂,没有自定义依赖解析器,只是Ninject给我的。然后我获取当前活动的内核,将其提供给插件并自行注册。
现在被击中的路线不起作用,我只得到任何外部路线的404,即使它们被命中并且控制器是(是三分检查)注册了Ninject内核。所以我想虽然Ninject已经注册了类型,但是在调用时,Mvc的DefaultControllerFactory找不到类型:
GetControllerTypeWithinNamespaces(string controllerName, HashSet<string> namespaces)
目前令我困惑的一件事是,即使使用正确的命名空间也找不到它...但是,如果我在asp mvc项目中添加插件作为参考并运行,那么只是为了证明我的hypothisis它(没有更改任何代码,只是插件程序集是项目中的引用,所以它将最终在bin目录中)它将工作。击中路线,我得到了所需的输出......
所以在这一点上我想知道虽然MEF正在托管外部DLL,但它不会以某种方式与当前的AppDomain共享它......或者似乎很奇怪......
这对我来说是一个阻碍者,所以任何建议都会很棒!
答案 0 :(得分: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。
答案 1 :(得分:0)
听起来与此相关,当您尝试直接从内核实例化类时会发生什么?如果它可以工作,你可以创建自己的控制器工厂:
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,但我并不打扰控制器,而是依赖于resolver级别。
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));