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

发布于 2024-12-06 11:14:30 字数 1117 浏览 0 评论 0原文

我现在有一个相当复杂的项目,作为这个项目的一部分,我有一个 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 项目中的引用并运行它(不更改任何代码,只是插件程序集是项目中的引用,因此它将最终出现在 bin 目录中)工作。点击路线,我得到了所需的输出...

所以此时我想知道虽然 MEF 托管外部 DLL,但它没有以某种方式与当前的 AppDomain 或其他东西共享它...这看起来很奇怪.. !

目前这对我来说是一个障碍,所以任何建议都会很棒

I have got quite a complex project on the go at the moment, and as part of this I have a MEF layer which purely handles loading of plugins and then the newly loaded plugins expose their routes which are registered with asp.mvc and their controllers which are added to Ninject's bindings.

The problem however comes in when the dynamically added routes are hit (and they are hit, I have checked with route debugger) even with correctly added Namespaces for the plugin within the route. When I say I have added the namespaces I mean like below:

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

Just to give a little more context to this situation, I am inheriting from NinjectHttpApplication and not doing anything else, no custom controller factories, no custom dependency resolvers, just what Ninject gives me. Then I take the currently active Kernel, give it to the plugins and they register themselves.

Now the routes that are hit do not work, I just get a 404 for any external routes, even though they are hit and the controller is (yes tripple checked) registered with the Ninject Kernel. So I am thinking that although Ninject has the type registered, Mvc's DefaultControllerFactory cannot find the type when calling through to:

GetControllerTypeWithinNamespaces(string controllerName, HashSet<string> namespaces)

One thing that baffles me at the moment though, is that it is not finding it even with the correct namespace... HOWEVER just to prove my hypothisis, if I add the plugin as a reference within the asp mvc project and run it (without changing any code, just the plugin assembly is a reference within the project, so it will end up within the bin directory) it will work. Hits the route and I get the desired output...

So at this point I am wondering if although MEF is hosting the external DLLs, it is not sharing it in some way with the current AppDomain or something... which seems odd...

This is a blocker for me at the moment, so any advice would be great!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

少女情怀诗 2024-12-13 11:14:30

似乎 DefaultControllerFactory 不知道哪种类型负责处理请求。您必须找出为什么 DefaultControllerFactory 不了解这些控制器,或者提供您自己的能够处理这些情况的实现。这个问题肯定与 MEF 相关,而不是与 Ninject 相关。

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。

It seems the DefaultControllerFactory does not know which type is responsible for handling the requests. You have either to find out why the DefaultControllerFactory does not know about these controllers or provide your own implementation that is able to handle these cases. The problem is definitely more MEF related than Ninject related.

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
    }
}

Another solution is to use Ninject'ss assembly loading mechanism instead of MEF.

触ぅ动初心 2024-12-13 11:14:30

听起来与 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,我不关心控制器工厂,而是在依赖解析器级别进入。

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);
    }
}

注意:两者都需要分别在 application_start 中注册(尽管您只使用一个)

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

DependencyResolver.SetResolver(new NinjectDependencyResolver(_kernel));

Sounds mef related, what happens when you try to instantiate the classes from the kernel directly yourself? If it works you could just create your own controller factory:

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);
    }
}

Although these days with mvc 3 I don't bother with the controllerfactory and go in at dependency resolver level.

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. both need to be registed in application_start respectively (although you'd only use one)

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

DependencyResolver.SetResolver(new NinjectDependencyResolver(_kernel));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文