2013-02-15 27 views
12

我在Asp.Net MVC 4項目中解決了404響應問題。它內置於VS2012目標4.5。404外部程序集中的控制器

我有預編譯的視圖和控制器內置到獨立的DLL。我可以動態加載DLL並從我的核心項目中檢查它們,甚至可以調用它們上的方法;但是,似乎MVC框架並不知道控制器。我在這裏,但有一些缺失。在控制器和視圖

控制器

背景是建立在一個獨立的MVC項目,並從Controller繼承。那裏沒有太有趣的事情發生。視圖使用RazorGenerator併成爲生活在項目中的類。

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

DLL在庫中的一個單獨的類(不是控制器的一部分)中實現了一個特定的接口,我們將其稱爲IPlugin

加載的DLL

運行在Visual Studio中管理我編譯我的應用程序,這是IIS下主辦。隨着項目的建成,我將一個插件DLL下載到我的「插件」目錄中。如果不進行調試(稍後會變得很重要),我打開IE並導航到該網站。 請注意,在這一點上,應用程序已經建成,但從未運行,所以啓動事件將觸發。如果我回收應用程序池,這裏的一切仍然一致。

我有一個Startup類兩種方法,PreStartPostStart和分別使用WebActivator.PreApplicationStartMethodWebActivator.PostApplicationStartMethod調用方法。

PreStart是我做到以下幾點:

  • 獲取所有插件的DLL文件在我的「插件」目錄
  • 複製所有插件AppDomain.CurrentDomain.DynamicDirectory
  • 負載類型...如果它包含一個IPlugin我再
    • 裝配添加到BuildManager
    • 調用一些方法對小鬼類lements IPlugin

在 '開始後' 我做這個代碼位(基於從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在該上下文中是一個鍵/值對,其中值是加載的程序集。此代碼的目的是通過爲每個知道如何解析視圖的組件添加視圖引擎(這是RazorGenerator的一部分)來確保MVC瞭解視圖。

我怎麼知道我關閉(但明顯缺乏雪茄)

IPlugin定義了一個名爲RegisterRoutes方法,其中,你猜對了,路都被註冊爲那些誰實現的接口。我在PreStart中調用此方法,並添加了路由 - 我已驗證這些路由表存在於我的路由表中。例如,PreStart期間在我的插件,通過該方法的動態調用創建定義的路線上,我看到這樣的事情作爲DataToken檢查我的路由時:

Namespaces = Plugin.Name.Controllers 

因此,路由被註冊時,程序集已加載,我已驗證該DLL已正確複製到AppDomain的DynamicDirectory。我可以調用在運行時動態加載的類的成員。但是當我導航到路由匹配的URL時,我得到一個404。這是而不是 a「找不到視圖」YSOD,它更類似於根本找不到控制器。

這裏是混淆了我的部分:如果在這一點上,沒有做任何事情,我返回到Visual Studio並擊中F5 ...一切正常。

這就像Visual Studio以某種我無法識別的方式瞭解控制器,並且MVC框架正在採用它。

最後,一問

我缺少什麼,怎麼做我得到的MVC框架要知道我的控制器嗎?

嘿,在這一點上,如果你還在讀這個,謝謝。 :)

+0

1. VS是否正在使用Cassini?嘗試將其更改爲IIS Express並檢查它是否繼續正常工作。 2.嘗試安裝[RouteDebugger](http://nuget.org/packages/routedebugger) - 也許它可能會給你一些線索是否正確註冊IIS – Pranav 2013-02-18 06:24:00

+0

感謝@Pranav,但它已經在IIS上。路由調試器顯示路由正在工作。 – MisterJames 2013-02-18 17:12:25

+1

這可能是一個問題? http://stackoverflow.com/questions/14971895/using-precompiledmvcengine-findview-throws-invalidoperationexception-and-looks-f – Tengiz 2013-02-22 17:29:01

回答

5

原來,這是Asp.Net本身的錯誤。

在討論與Eilon立頓的Asp的問題。Net團隊,並認爲這是MVC框架中的一些不妥之處,Eilon和幾個團隊成員挖掘了一些事情,發現這個對話的錯誤程度較低:http://aspnetwebstack.codeplex.com/discussions/403529

他們還提出了一種解決方法,呼籲BuildManager調用AddReferencedAssembly,這是我通過下面的代碼執行後:

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

這使您可以在啓動時在你的應用程序初始化前階段的工作增添額外的控制器/編譯意見。我現在正在做的是遍歷我的插件目錄中的DLL列表並將它們推送到BuildManager,如上所述。

這裏唯一的限制是你不能刪除程序集或動態清除緩存。我發現要做到這一點的唯一方法是將以前未知的程序集添加到引用的程序集和編譯依賴項中。我正在嘗試在應用程序初始化初始化期間動態地發佈一個新程序集,以便始終有效地清除緩存並通過僞造一個新程序集來刪除以前包含的插件。

希望這可以幫助別人。

乾杯。

+0

非常感謝您的詳細問題和答案。我沒有得到的一件事是爲什麼你不使用自定義控制器工廠(參見'ControllerBuilder.Current.SetControllerFactory')?這將允許您完全控制何時產生哪個控制器,不是嗎? – Dejan 2015-10-21 14:45:40

1

它看起來像這樣的問題:

MVC使用的視圖引擎從不同的視圖引擎 歧義視圖緩存條目集限定類型名稱。 所以它的 不可能有多個PrecompiledMvc​​Engine對象(如果在多個程序集中有預編譯視圖,則爲 )。 問題可以通過從每個程序集的 PrecompiledMvc​​Engine創建一個不同派生類來解決。或者通過創建一個單一的 泛型派生類,使用程序集中的某種類型進行參數化。

Article is here

+0

謝謝Nenad,但目前我只運行一個插件,所以只有一個試圖加載。這可能是因素,但我也有2個插件同時運行,所以我不確定它會。此外,這並沒有解決我在控制器沒有找到的問題。這是賞金的關鍵。乾杯。 – MisterJames 2013-02-22 15:27:32

+0

你能提供更多關於錯誤的細節嗎?堆棧跟蹤? – Nenad 2013-02-22 15:35:08

+0

我希望有。當我嘗試訪問一個視圖時,所有我在控制器上都是404。我有Log4Net和ELMAH,並且沒有任何問題,我正在接受(每一步記錄)。我在本週與Asp.Net團隊的一些成員討論過一些事情之後,會提供更多詳細信息。 – MisterJames 2013-02-22 15:45:36

0

@MisterJames,看看這個:

Asp.Net Mvc Pluggable Application

我希望它是有用的。

+0

Felipe,這是在同一解決方案中使用項目中的區域,是一種完全不同的方法。我的需求是爲插件提供獨立的解決方案。我會更詳細地評估這一點,看看是否有任何線索,但就目前情況而言,我不認爲這會對我的情況有所幫助。 – MisterJames 2013-02-22 15:30:27