404在外部组件控制器控制器、组件

2023-09-04 01:54:24 作者:哑巴诉爱.

我无法解决我的Asp.Net MVC 4项目404响应。它建于VS2012针对4.5。

I am having trouble resolving 404 responses in my Asp.Net MVC 4 project. It's built in VS2012 targeting 4.5.

我都内置了独立的DLL pre-编译视图和控制器。我能够动态加载的DLL和我的核心项目检查它们,即使调用它们的方法;然而,似乎MVC框架是不知道的控制器。我靠近这里,但有一些人失踪。

I have pre-compiled views and controllers built into stand-alone DLLs. I am able to dynamically load the DLLs and inspect them from my core project, even invoke methods on them; however, it seems that the MVC Framework is not aware of the controllers. I am close here, but there is something missing.

背景上的控制器和视图

控制器是建立在一个独立的MVC项目,并从控制器继承。没有什么太有意思的事情出现。该视图使用RazorGenerator,成为生活在项目中的类。

Controllers are built in a stand-alone MVC project and inherit from Controller. Nothing too interesting going on there. The views use RazorGenerator and become classes that live in the project.

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

The output of the project is a DLL which correctly contains the controllers and views.

在DLL中实现一个特定的接口,我们把它叫做 IPlugin ,在图书馆一个单独的类(控制器的一部分)。

The DLLs implement a specific interface, we'll call it IPlugin, in a separate class (not part of a controller) in the library.

加载的DLL

运行作为管理员在Visual Studio我编译我的应用程序,这是IIS下主办。随着项目的建成,我滴个插件DLL到我的插件目录。如果没有调试(这将成为重要的更新版本),我打开IE浏览器,浏览到该网站。 需要注意的是,在这一点上,应用程序已经建成,但从来没有运行,因此启动事件将触发。这里的一切都还是一致的,如果我回收的应用程序池。的

Running as admin in Visual Studio I compile my app, which is hosted under IIS. With the project built, I drop a plugin DLL into my "Plugins" directory. Without debugging (this becomes important later), I open IE and navigate to the site. Note that at this point the App has been built, but never run, so startup events will fire. Everything here is still consistent if I recycle the app pool.

我有一个启动类有两个方法, preSTART PostStart 和使用 WebActivator。preApplicationStartMethod WebActivator.PostApplicationStartMethod 分别调用方法。

I have a Startup class with two methods, PreStart and PostStart and invoke the methods using WebActivator.PreApplicationStartMethod and WebActivator.PostApplicationStartMethod respectively.

preSTART 是我做到以下几点:

让我的插件目录中的所有插件的DLL列表 复制所有插件 AppDomain.CurrentDomain.DynamicDirectory 加载类型...如果它包含一个 IPlugin 然后我 组装添加到BuildManager 在调用一些对实现IPlugin类中的方法 Get a list of all the plugin DLLs in my "Plugins" directory Copy all plugins to AppDomain.CurrentDomain.DynamicDirectory Load the type...if it contains an IPlugin I then Add the assembly to the BuildManager Call some of the methods on the class that implements IPlugin

在PostStart我做了code此位(基于RazorGenerator.Mvc code):

In 'PostStart' I do this bit of code (based on code from 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);
}

模块在这种情况下是键/值对其中的值是加载的程序集。这code的目的是为了确保MVC是知道的意见,通过添加视图引擎为每个知道如何解决的意见汇编(这是RazorGenerator的一部分)。

Modules in this context is a key/value pair where the values are the loaded assemblies. The purpose of this code is to make sure that MVC is aware of the views by adding a view engine for each assembly that knows how to resolve the views (this is part of RazorGenerator).

我怎么知道我关闭(但明显缺乏雪茄)

IPlugin 定义的RegisterRoutes 称为方法,其中,你猜对了,路都被注册为那些谁实施的接口。我把这种方法 preSTART 和路由添加 - 我已经验证了这些存在于我的路由表。举例来说,在我的插件定义的路由,通过该方法在检查我的路线,当 preSTART ,我看到这样的事情作为一个DataToken动态调用创建

IPlugin defines a method called RegisterRoutes where, you guessed it, routes are to be registered for those who implement the interface. I call this method in PreStart and routes are added - I have verified that these exist in my route table. For instance, on a route defined in my plugin, created through dynamic invocation of the method during the PreStart, I see something like this as a DataToken when examining my routes:

Namespaces = Plugin.Name.Controllers

因此​​,该路由记录,该程序集加载,我已经验证DLL是否正确地复制到AppDomain中的DynamicDirectory。我能够调用的是动态加载运行时类的成员。但是,当我浏览到有匹配的路由URL的我收到了404 。这是的没有的一个无法找到视图YSOD,它更类似于没有找到控制器的。

So, the route is registered, the assembly is loaded, I have verified that the DLL is correctly copied to the DynamicDirectory of the AppDomain. I am able to invoke members of classes that are loaded dynamically at runtime. But when I navigate to the URL that is matched by the route I get a 404. This is not a "could not locate view" YSOD, it's more akin to not finding the controller at all.

这是混淆了赫克了我的一部分:如果在这一点上,没有做任何事情,我返回到Visual Studio,然后按F5 ......一切工作

Here is the part that confuses the heck out of me: if, at this point, without doing anything, I return to Visual Studio and hit F5...everything works.

这就像Visual Studio是意识到在某些方面,我不能识别控制器,以及MVC框架是它捡了。

It's like Visual Studio is becoming aware of the controller in some way that I can't identify, and the MVC Framework is picking up on it.

最后,一问

我在想什么,以及如何让MVC框架要知道我的控制器?

What am I missing, and how do I get the MVC Framework to be aware of my controller?

哎,在这一点上,如果你还在读这篇文章,谢谢。 :)

And hey, at this point, if you're still reading this, thanks. :)

推荐答案

原来,这是Asp.Net本身。

Turns out that this is a bug in Asp.Net itself.

与Asp.Net队Eilon立顿讨论这个问题,并认为这是在MVC框架的东西不对劲后,Eilon和几个队员挖成的东西,发现误差为每这场谈话较低水平: HTTP://aspnetwebstack.$c$cplex.com/discussions/403529

After discussing the issue with Eilon Lipton of the Asp.Net team, and thinking this was something amiss in the MVC Framework, Eilon and a couple team members dug into things and found that the error was at a lower level per this conversation: http://aspnetwebstack.codeplex.com/discussions/403529

他们还提出了一个解决办法,其中包括另一个电话上 BuildManager ,来电后 AddReferencedAssembly ,这是我通过实施以下code:

They also suggested a workaround that included another call on BuildManager after the call to AddReferencedAssembly, which I implemented via the following code:

    // Add the plugin as a reference to the application
    BuildManager.AddReferencedAssembly(assembly);
    BuildManager.AddCompilationDependency(assembly.FullName);

这可以让你在你的pre-应用程序初始化阶段添加额外的控制器/编译看法启动。我现在做的是遍历在我的插件目录下的DLL列表,并将其推到 BuildManager 如上。

This allows you to add additional controllers/compiled views at startup in your pre-application init stage. What I'm doing now is looping through the list of DLLs in my plugins directory and pushing them to BuildManager as above.

这里唯一的限制是,你不能的删除的组件或动态清除缓存。我发现做到这一点的唯一方法是pviously未知的组装加$ P $的引用的程序集和编译的依赖。我尝试用pre-应用程序初始化过程中动态地散发出新的组件,这样我可以随时,有效,清除缓存,并通过伪造一个新的组件,删除previously包括插件。

The only limitation here is that you can't remove assemblies or clear the cache dynamically. The only way that I've found to do this is to add a previously unknown assembly to the referenced assemblies and compilation dependencies. I am experimenting with dynamically emitting a new assembly during pre-application initialization so that I can always, effectively, clear the cache and remove previously included plugins by faking a new assembly.

希望这可以帮助别人那里。

Hope this helps someone else out there.

干杯。