2011-06-24 76 views
13

我正在爲使用Razor視圖的ASP.NET MVC3設計插件框架,並且我遇到了使嵌入式視圖正常工作的問題。ASP.NET MVC3和嵌入式Razor視圖的插件框架

插件框架被設計爲具有以下功能:

  • 每個插件都有自己的模型,控制器和視圖。的意見是嵌入式資源,並從PluginController類派生
  • 所述插件具有到共享類庫定義PluginController基類
  • 承載插件的「殼」的web應用程序的依賴性的引用控制器在設計時間處不得持有對任何插件的引用,因爲它在設計時不知道它具有哪些插件。
    1. 發現插件(使用反射)
    2. 註冊:
    3. 插件DLL的在外殼應用程序的文件夾,這是不是/ bin文件夾
    4. 外殼採用的護理下降所有控制器(我正在使用Spring.Net)
    5. 創建路由到控制器
    6. 通過自定義VirtualPathProvider服務剃鬚刀文件(cshtml)

現在一切工作正常,除了當嵌入的視圖引用插件DLL中的類型。然後我得到了臭名昭著的錯誤(名字省略了):

The type or namespace name '[Plugins]' does not exist in the namespace '[MyPluginSolution]' (are you missing an assembly reference?)

這樣做的原因是,它被調用運行的CSC編譯器來編譯剃刀意見只得到bin文件夾中的dll引用和GAC

我也嘗試過使用this technique預編譯視圖,但最終它給出了相同的結果,因爲運行時堅持編譯預編譯的剃刀視圖的包裝。

我當然可以刪除插件DLL的/ bin文件夾,但我的問題是:

是否有在非斌註冊的dll方式(和非GAC)文件夾,和治療他們是「一等公民」,所以他們可以用剃刀的意見?

回答

14

好了,該解決方案是使用this article發現。

首先我創建一個類PreApplicationStartMethod。此方法掃描插件文件夾並將dll複製到AppDomain.DynamicDirectory

然後,每個這些DLL的加載使用BuildManager.AddReferencedAssembly

而且,強烈類型的剃刀視圖編譯得很漂亮。看到代碼在這裏:

[assembly: PreApplicationStartMethod(typeof(MySolution.PluginHandler.PluginActivator), "Initialize")] 
namespace MySolution.PluginHandler 
{ 
    public class PluginActivator 
    { 
     private static readonly DirectoryInfo PluginFolderInfo; 

     static PluginActivator() { 
      PluginFolderInfo = new DirectoryInfo(HostingEnvironment.MapPath("~/plugins")); 
     } 

     public static void Initialize() { 
      CopyPluginDlls(PluginFolderInfo, AppDomain.CurrentDomain.DynamicDirectory); 
      LoadPluginAssemblies(AppDomain.CurrentDomain.DynamicDirectory); 
     } 

     private static void CopyPluginDlls(DirectoryInfo sourceFolder, string destinationFolder) 
     { 
      foreach (var plug in sourceFolder.GetFiles("*.dll", SearchOption.AllDirectories)) { 
       if (!File.Exists(Path.Combine(destinationFolder, plug.Name))) { 
        File.Copy(plug.FullName, Path.Combine(destinationFolder, plug.Name), false); 
       } 
      } 
     } 

     private static void LoadPluginAssemblies(string dynamicDirectory) 
     { 
      foreach (var plug in Directory.GetFiles(dynamicDirectory, "*.dll", SearchOption.AllDirectories)) { 
       Assembly assembly = Assembly.Load(AssemblyName.GetAssemblyName(plug)); 
       BuildManager.AddReferencedAssembly(assembly); 
      } 
     } 
    } 
} 

我希望這可以幫助其他程序員,希望使用這些新技術創建一個乾淨的插件框架。

+0

是不是在插件目錄中插入插件的原因是你不希望應用程序重新啓動?此解決方案僅在應用程序啓動時加載插件(BuildManager.AddReferencedAssembly) - 是否可以在dynamicDirectory中動態引用程序集? –

+0

原因是這個解決方案可能有大量的插件,每個插件有3-5個dll。由於您無法將它們放入/ bin下的子文件夾中,因此首選解決方案是使用另一個文件夾。 – lasseschou

1

David Ebbo最近發佈了關於預編譯Razor視圖到程序集的博客。您可以查看帖子here

你應該能夠避免直接通過動態加載程序集來註冊程序集(我通常使用IoC容器來做這個),然後爲每個插件程序集調用BuildManager.AddReferencedAssembly。

+0

謝謝本。但就他的情況而言,就像在Chris van de Steeg的案例中一樣,宿主應用程序直接引用了插件程序集,所以它不能很好地解決我的問題。 – lasseschou

+0

我已經更新了我的答案,但請注意這是所有「理論上」:) - 更多詳情http://haacked.com/archive/2010/05/16/three-hidden-extensibility-gems-in-asp-net -4.aspx –

+0

嗨,本,你最近的編輯指出我正確的方向。解決方案是包含一個預先Application_Start方法,將所有插件dll複製到AppDomain.DynamicDirectory,然後調用BuildManager.AddReferencedAssembly()。本文展示瞭如何在完全信任和中等信任下執行此操作:http://shazwazza.com/post/Developing-a-plugin-framework-in-ASPNET-with-medium-trust.aspx。我會在這裏發佈答案。 – lasseschou

1

請看看NOPCommerce的源代碼。它具有很好的基於Shannon工作的插件框架。

1

你也可以在MVC3和4中使用「區域」功能,你可以創建一個漂亮的插件系統。它將處理插件的模型,視圖和控制器分離到它自己的程序集中。

相關問題