關於外部程序集中的控制器的404

[英]404 on Controllers in External Assemblies


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

我在Asp中解決404響應時遇到了麻煩。凈MVC項目4。它內置在VS2012,目標是4.5。

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.

我將預編譯的視圖和控制器內置到獨立dll中。我能夠動態地加載dll並從我的核心項目中檢查它們,甚至調用它們的方法;但是,MVC框架似乎不知道控制器。我離這里很近,但缺少了一些東西。

Background on the Controllers and Views

控制器和視圖的背景

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.

控制器構建在一個獨立的MVC項目中,並從控制器繼承。沒有什么有趣的事。視圖使用RazorGenerator並成為項目中的類。

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

項目的輸出是一個DLL,它正確地包含了控制器和視圖。

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

dll在庫中的一個單獨的類(不是控制器的一部分)中實現一個特定的接口,我們稱之為IPlugin。

Loading the DLLs

加載dll

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.

在Visual Studio中以管理員的身份運行我的應用程序,它托管在IIS下。項目完成后,我將一個插件DLL放到我的“插件”目錄中。無需調試(這在以后會變得很重要),我打開IE並導航到站點。注意,此時應用程序已經構建,但從未運行,因此啟動事件將啟動。如果我回收應用程序池,這里的一切都是一致的。

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

我有一個包含兩個方法的Startup類,即PreStart和PostStart,並使用WebActivator調用這些方法。PreApplicationStartMethod WebActivator。PostApplicationStartMethod分別。

PreStart is where I do the following:

PreStart是我做以下事情的地方:

  • Get a list of all the plugin DLLs in my "Plugins" directory
  • 獲取我的“插件”目錄中所有插件dll的列表
  • Copy all plugins to AppDomain.CurrentDomain.DynamicDirectory
  • 將所有插件復制到AppDomain.CurrentDomain.DynamicDirectory
  • Load the type...if it contains an IPlugin I then
    • Add the assembly to the BuildManager
    • 將程序集添加到BuildManager
    • Call some of the methods on the class that implements IPlugin
    • 調用實現IPlugin類上的一些方法
  • 負載的類型……如果它包含一個IPlugin,那么我將程序集添加到BuildManager調用實現IPlugin的類上的一些方法

In 'PostStart' I do this bit of code (based on code from RazorGenerator.Mvc):

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

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).

這個上下文中的模塊是一個鍵/值對,其中值是加載的程序集。這段代碼的目的是通過為每個知道如何解析視圖的程序集添加視圖引擎(這是RazorGenerator的一部分)來確保MVC能夠識別視圖。

How I Know I'm Close (but Clearly Lacking the Cigar)

我怎么知道我很接近(但顯然沒有雪茄)

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:

IPlugin定義了一個名為registerroute的方法,在這個方法中,實現接口的路由被注冊。我在PreStart中調用這個方法,並添加路由——我已經驗證這些方法存在於我的路由表中。例如,在我的插件中定義的路線,通過在開始前的方法的動態調用創建的路線,我在檢查我的路線時看到類似這樣的東西作為一個DataToken:

Namespaces = Plugin.Name.Controllers

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.

因此,注冊了路由,裝載了程序集,我驗證了DLL被正確復制到AppDomain的DynamicDirectory。我可以調用在運行時動態加載的類的成員。但是當我導航到與路徑匹配的URL時,我得到404。這不是“無法定位視圖”YSOD,它更像是根本找不到控制器。

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,點擊F5……一切工作。

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.

就好像Visual Studio正在以某種我無法識別的方式意識到控制器,而MVC框架正在利用它。

Finally, A Question

最后,一個問題

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

我遺漏了什么,以及如何讓MVC框架意識到我的控制器?

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

現在,如果你還在讀這個,謝謝。:)

3 个解决方案

#1


5  

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

這是Asp中的一個錯誤。網絡本身。

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

在與Asp的Eilon Lipton討論這個問題之后。Eilon和幾個團隊成員深入研究后發現,在這個對話中錯誤的級別更低:http://aspnetwebstack.codeplex.com/discussions/403529

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

他們還提出了一個解決方案,其中包括在調用AddReferencedAssembly之后對BuildManager進行另一個調用,我通過以下代碼實現了這個調用:

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

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.

這允許您在應用程序前初始化階段的啟動階段添加額外的控制器/編譯視圖。我現在正在做的是循環遍歷我的插件目錄中的dll列表,並將它們推到上面的BuildManager。

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.

希望這能幫助別人。

Cheers.

歡呼。

#2


1  

It looks like this issue:

這個問題看起來是這樣的:

MVC uses assembly-qualified type name of the view engine to disambiguate view cache entries from different view engines. So it's not possible to have more than one PrecompiledMvcEngine object (as when you have precompiled views in more than one assembly). The problem can be solved by creating a different derived class from PrecompiledMvcEngine for each assembly. Or by creating a single generic derived class parameterized with some type from the assembly.

MVC使用視圖引擎的程序集限定類型名稱來消除來自不同視圖引擎的視圖緩存條目的歧義。因此,不可能有多個PrecompiledMvcEngine對象(就像在多個程序集中擁有預編譯視圖一樣)。這個問題可以通過為每個程序集創建來自PrecompiledMvcEngine的不同派生類來解決。或者通過使用程序集中的某種類型創建一個泛型派生類參數化。

Article is here.

文章在這里。

#3


0  

@MisterJames, take a look at this:

@MisterJames,看看這個:

Asp.Net Mvc Pluggable Application

Asp。Net Mvc可插入應用程序

I hope it's useful.

我希望它是有用的。


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2013/02/15/72f544cac33b185b882acf08e71605e1.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com