Ninject.Web.Mvc知道动态加载的控制器,但ASP.Mvc不是吗?

时间:2011-09-27 11:05:46

标签: asp.net-mvc ninject

我现在有一个非常复杂的项目,作为其中的一部分,我有一个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共享它......或者似乎很奇怪......

这对我来说是一个阻碍者,所以任何建议都会很棒!

2 个答案:

答案 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));