外部组件中的控制器上的404

Mis*_*mes 13 .net asp.net-mvc assemblies asp.net-mvc-4

我在Asp.Net MVC 4项目中解决404响应时遇到问题.它内置于VS2012,目标4.5.

我有预编译的视图和控制器内置到独立的DLL中.我能够动态加载DLL并从我的核心项目中检查它们,甚至调用它们的方法; 但是,似乎MVC框架并不知道控制器.我在附近,但有些东西不见了.

控制器和视图的背景

控制器构建在独立的MVC项目中并继承自Controller.没有什么太有趣了.视图使用RazorGenerator并成为项目中的类.

项目的输出是一个DLL,它正确包含控制器和视图.

这些DLL IPlugin在库中的一个单独的类(不是控制器的一部分)中实现一个特定的接口,我们称之为它.

加载DLL

在Visual Studio中以管理员身份运行我编译我的应用程序,该应用程序在IIS下托管.随着项目的建立,我将插件DLL放入我的"插件"目录.没有调试(这在以后变得很重要),我打开IE并导航到该站点. 请注意,此时App已构建,但从未运行,因此将启动启动事件.如果我回收应用程序池,这里的一切仍然是一致的.

我有Startup两种方法类,PreStartPostStart使用调用方法WebActivator.PreApplicationStartMethodWebActivator.PostApplicationStartMethod分别.

PreStart 我在哪里做以下事情:

  • 获取我的"插件"目录中的所有插件DLL的列表
  • 将所有插件复制到 AppDomain.CurrentDomain.DynamicDirectory
  • 加载类型...如果它包含IPlugin我那么
    • 将程序集添加到BuildManager
    • 调用实现IPlugin的类的一些方法

在'PostStart'中我做了一些代码(基于RazorGenerator.Mvc的代码):

foreach (var assembly in Modules.Select(m=>m.Value))
{
    var engine = new PrecompiledMvcEngine(assembly)
    {
        UsePhysicalViewsIfNewer = HttpContext.Current.Request.IsLocal
    };

    ViewEngines.Engines.Insert(0, engine);
    VirtualPathFactoryManager.RegisterVirtualPathFactory(engine);
}
Run Code Online (Sandbox Code Playgroud)

Modules在此上下文中是键/值对,其中值是加载的程序集.此代码的目的是通过为知道如何解析视图的每个程序集添加视图引擎来确保MVC知道视图(这是RazorGenerator的一部分).

我怎么知道我很接近(但显然缺乏雪茄)

IPlugin定义一个名为RegisterRouteswhere 的方法,你猜对了,为那些实现接口的人注册了路由.我调用此方法PreStart并添加路由 - 我已经验证了这些存在于我的路由表中.例如,在我的插件中定义的路由,通过在此期间动态调用方法创建的路径PreStart,我在检查路由时看到类似这样的DataToken:

Namespaces = Plugin.Name.Controllers
Run Code Online (Sandbox Code Playgroud)

因此,路由已注册,程序集已加载,我已验证DLL已正确复制到AppDomain的DynamicDirectory.我可以调用在运行时动态加载的类的成员.但是当我导航到路线匹配的URL时,我得到了404.这不是 "无法定位视图"YSOD,它更类似于根本找不到控制器.

这部分让我感到困惑:如果在这一点上没有做任何事情,我会回到Visual Studio并点击F5 ......一切正常.

这就像Visual Studio以某种方式逐渐意识到控制器,我无法识别,MVC框架正在接受它.

最后,一个问题

我缺少什么,以及如何让MVC框架了解我的控制器?

嘿,在这一点上,如果你还在读这个,谢谢.:)

Mis*_*mes 6

事实证明,这是Asp.Net本身的一个错误.

在与Asp.Net团队的Eilon Lipton讨论这个问题之后,并认为这在MVC框架中有些不妥,Eilon和几个团队成员挖掘了一些东西,发现每个对话的错误都在较低的水平:http:http: //aspnetwebstack.codeplex.com/discussions/403529

他们还提出了一个解决方法,其中包括调用BuildManager后的另一个调用AddReferencedAssembly,我通过以下代码实现:

    // Add the plugin as a reference to the application
    BuildManager.AddReferencedAssembly(assembly);
    BuildManager.AddCompilationDependency(assembly.FullName);
Run Code Online (Sandbox Code Playgroud)

这允许您在预应用程序初始化阶段启动时添加其他控制器/编译视图.我现在正在做的是循环遍历我的插件目录中的DLL列表并将它们推送到BuildManager上面.

此处唯一的限制是您无法动态删除程序集或清除缓存.我发现这样做的唯一方法是将以前未知的程序集添加到引用的程序集和编译依赖项中.我正在尝试在预应用程序初始化期间动态发出新程序集,以便我可以通过伪造新程序集始终有效地清除缓存并删除以前包含的插件.

希望这有助于其他人.

干杯.