久久96国产精品久久久-久久发布国产伦子伦精品-久久精品国产精品青草-久久天天躁夜夜躁狠狠85麻豆

技術員聯盟提供win764位系統下載,win10,win7,xp,裝機純凈版,64位旗艦版,綠色軟件,免費軟件下載基地!

當前位置:主頁 > 教程 > 服務器類 >

如何使用ASP.NET MVC引擎開發插件系統

來源:技術員聯盟┆發布時間:2017-06-16 00:43┆點擊:

我心中的插件系統應該是像Nop那樣(更牛逼的如Orchard,OSGI.NET),每個插件模塊不只是一堆實現了某個業務接口的dll,然后采用反射或IOC技術來調用,而是一個完整的mvc小應用,我可以在后臺控制插件的安裝和禁用,目錄結構如下:

如何使用ASP.NET MVC引擎開發插件系統 三聯

生成后放在站點根目錄下的Plugins文件夾中,每個插件有一個子文件夾

Plugins/Sms.AliYun/

Plugins/Sms.ManDao/

我是一個有強迫癥的的懶人,我不想將生成的dll文件拷貝到bin目錄。

二、要解決的問題

1.asp.net引擎默認只會加載“bin”文件夾中的dll,而我們想要的插件文件則是分散在Plugins目錄下的各個子目錄中。

2.視圖中使用了模型時如何處理?默認情況下RazorViewEngine使用BuildManager將視圖編譯成動態程序集,然后使用Activator.CreateInstance實例化新編譯的對象,而使用插件dll時,當前的AppDomain不知道如何解析這種引用了模型的視圖,因為它不存在于“bin”或GAC中。更糟糕的是,不會收到任何錯誤消息,告訴您為什么它不工作,或者問題在哪。相反,他會告訴你,從View目錄中找不到文件。

3.某個插件正掛在站點下運行著,直接覆蓋插件的dll,會告訴你當前dll正在使用,不能被覆蓋。

4.視圖文件不放站點的View目錄中,該如何加載。

三.Net 4.0讓這一切變成可能

Net4.0有一個新特性是在應用程序初始化之前執行代碼的能力(PreApplicationStartMethodAttribute),這個特性使得應用程序在Application_Star前可以做一些工作,例如我們可以在應用啟動之前告知我們的mvc插件系統的dll放在哪,做預加載處理等。關于.net的幾個新特性,有歪果仁寫得有博客來介紹,點我。,關于PreApplicationStartMethodAttribute,有博友已經寫過了,點我。 Abp的啟動模塊應該也是使用PreApplicationStartMethodAttribute這個特性原理來實現的,具體是不是這樣還沒看。

四、解決方案

1.修改主站點web.config目錄,讓運行時除了加載bin目錄中的文件,還可以從其它目錄加載

<runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath="Plugins/temp/" /> </assemblyBinding> </runtime>

2.開發一個簡易的插件管理類,這個類的作用就是在Application_Start之前就把Plugins各子目錄中的dll拷貝到第1步指定的文件夾中,為了讓demo盡可能簡單,沒有對重復的dll進行檢測(比如插件中引用了ef程序集,主站點也引用了,在站點bin目錄中已經存在ef的dll了,就沒必要再把插件中的dll拷貝到上面設置的動態程序集目錄中)

using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Web; using System.Web.Compilation; using System.Web.Hosting; [assembly: PreApplicationStartMethod(typeof(Plugins.Core.PreApplicationInit), "Initialize")] namespace Plugins.Core { public class PreApplicationInit { static PreApplicationInit() { PluginFolder = new DirectoryInfo(HostingEnvironment.MapPath("~/plugins")); ShadowCopyFolder = new DirectoryInfo(HostingEnvironment.MapPath("~/plugins/temp")); } /// <summary> /// 插件所在目錄信息 /// </summary> private static readonly DirectoryInfo PluginFolder; /// <summary> /// 程序應行時指定的dll目錄 /// </summary> private static readonly DirectoryInfo ShadowCopyFolder; public static void Initialize() { Directory.CreateDirectory(ShadowCopyFolder.FullName); //清空插件dll運行目錄中的文件 foreach (var f in ShadowCopyFolder.GetFiles("*.dll", SearchOption.AllDirectories)) { f.Delete(); } foreach (var plug in PluginFolder.GetFiles("*.dll", SearchOption.AllDirectories).Where(i=>i.Directory.Parent.Name== "plugins")) { File.Copy(plug.FullName, Path.Combine(ShadowCopyFolder.FullName, plug.Name), true); } foreach (var a in ShadowCopyFolder .GetFiles("*.dll", SearchOption.AllDirectories) .Select(x => AssemblyName.GetAssemblyName(x.FullName)) .Select(x => Assembly.Load(x.FullName))) { BuildManager.AddReferencedAssembly(a); } } } }

3.如何讓View引擎找到我們的視圖呢?答案是重寫RazorViewEngine的方法,我采用了約定大于配置的方式(假設我們的插件項目命名空間為Plugins.Apps.Sms,那么默認的控制器命名空間為Plugins.Apps.Sms.Controllers,插件生成后的文件夾必須為/Plugins/Plugins.Apps.Sms/),通過分析當前控制器就可以知道當前插件的View目錄位置