• <fieldset id="8imwq"><menu id="8imwq"></menu></fieldset>
  • <bdo id="8imwq"><input id="8imwq"></input></bdo>
    最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
    問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
    當前位置: 首頁 - 科技 - 知識百科 - 正文

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

    來源:懂視網 責編:小采 時間:2020-11-27 22:35:44
    文檔

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

    使用ASP.NET MVC引擎開發插件系統:一、前言 我心中的插件系統應該是像Nop那樣(更牛逼的如Orchard,OSGI.NET),每個插件模塊不只是一堆實現了某個業務接口的dll,然后采用反射或IOC技術來調用,而是一個完整的mvc小應用,我可以在后臺控制插件的安裝和禁用,目錄結構如下: 生成后放在站點
    推薦度:
    導讀使用ASP.NET MVC引擎開發插件系統:一、前言 我心中的插件系統應該是像Nop那樣(更牛逼的如Orchard,OSGI.NET),每個插件模塊不只是一堆實現了某個業務接口的dll,然后采用反射或IOC技術來調用,而是一個完整的mvc小應用,我可以在后臺控制插件的安裝和禁用,目錄結構如下: 生成后放在站點

    一、前言

    我心中的插件系統應該是像Nop那樣(更牛逼的如Orchard,OSGI.NET),每個插件模塊不只是一堆實現了某個業務接口的dll,然后采用反射或IOC技術來調用,而是一個完整的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目錄位置

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.WebPages.Razor;
    
    namespace Plugins.Web
    {
     public class CustomerViewEngine : RazorViewEngine
     {
    
     /// <summary>
     /// 定義視圖頁所在地址。
     /// </summary>
     private string[] _viewLocationFormats = new[]
     {
     "~/Views/Parts/{0}.cshtml",
     "~/Plugins/{pluginFolder}/Views/{1}/{0}.cshtml",
     "~/Plugins/{pluginFolder}/Views/Shared/{0}.cshtml",
     "~/Views/{1}/{0}.cshtml",
     "~/Views/Shared/{0}.cshtml",
     };
     public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
     {
     string ns = controllerContext.Controller.GetType().Namespace;
     string controller = controllerContext.Controller.GetType().Name.Replace("Controller", "");
     //說明是插件中的控制器,View目錄需要單獨處理
     if (ns.ToLower().Contains("plugins"))
     {
     var pluginsFolder = ns.ToLower().Replace(".controllers", "");
     ViewLocationFormats = ReplacePlaceholder(pluginsFolder);
     }
     return base.FindView(controllerContext, viewName, masterName, useCache);
     }
     /// <summary>
     /// 替換pluginFolder占位符
     /// </summary>
     /// <param name="folderName"></param>
     private string[] ReplacePlaceholder(string folderName)
     {
     string[] tempArray = new string[_viewLocationFormats.Length];
     if (_viewLocationFormats != null)
     {
     for (int i = 0; i < _viewLocationFormats.Length; i++)
     {
     tempArray[i] = _viewLocationFormats[i].Replace("{pluginFolder}", folderName);
     }
     }
     return tempArray;
     }
     }
    }
    
    
    

    然后在主站點的Global.asax中將Razor引擎指定為我們重寫過的

    4.開始制作一個插件目錄,跟我們平時建立的MVC項目并沒有太大區別,只是發布時需要做一些設置。

    .生成路徑要按照第3條的約定來寫,不然會找不到視圖文件

    .View目錄下的web.config和.cshtml文件要復制到生成目錄(在文件中點右鍵)

    3.設置引用項目中的生成屬性,主程序下面已經有了的就把“復制到輸出目錄”設置為無,要不然拷貝到動態bin目錄時會出錯,可以對第2步中的那個類改造一下,加入文件比較功能,bin目錄中沒有的,才拷貝到動態bin目錄中。

    4.生成后的目錄結構如下:

    5.跑一下,一切正常,插件中的控制器工作正常,視圖中引用了Model也沒問題

    到此,一個插件系統的核心部分就算完成了,你可繼續進行擴展,增加插件的發現、安裝、卸載功能,這些相對于核心功能來說,都是小兒科。后續我會基于Abp框架出一個插件系統的文章,有興趣的把小板凳準備好,瓜子花生買上:)

    五、源代碼

    下載Plugins鏈接: https://pan.baidu.com/s/1nvmbL81 密碼: 85v1

    聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文檔

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

    使用ASP.NET MVC引擎開發插件系統:一、前言 我心中的插件系統應該是像Nop那樣(更牛逼的如Orchard,OSGI.NET),每個插件模塊不只是一堆實現了某個業務接口的dll,然后采用反射或IOC技術來調用,而是一個完整的mvc小應用,我可以在后臺控制插件的安裝和禁用,目錄結構如下: 生成后放在站點
    推薦度:
    • 熱門焦點

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top
    主站蜘蛛池模板: 西瓜精品国产自在现线| 中文字幕一精品亚洲无线一区| 久久精品国产99久久丝袜| 岛国精品一区免费视频在线观看| 国产精品网址在线观看你懂的 | 亚洲国产午夜中文字幕精品黄网站 | 亚洲精品国产综合久久一线| 98香蕉草草视频在线精品看| 精品国产a∨无码一区二区三区 | 国产精品免费大片一区二区| 国产精品香蕉在线观看| 久久99国产精品久久| 精品一区二区三区在线成人 | 无码人妻精品一区二区三18禁 | 国产精品一区二区不卡| 熟女精品视频一区二区三区 | 一区二区三区精品| 国产精品久久久久久久久| 精品午夜福利在线观看| 亚洲国产精品一区二区成人片国内| 欧美日韩成人精品久久久免费看 | 亚州日韩精品专区久久久| 国产日韩精品无码区免费专区国产| 免费视频精品一区二区三区| jizz国产精品网站| 国内精品久久久久影院优| 久久精品国产久精国产思思| 无码人妻精品中文字幕| 无码国产精品一区二区免费vr | 国产在线精品网址你懂的| 国产精品偷伦视频观看免费| 精品久久无码中文字幕| 久久国产精品无码HDAV| 四虎成人精品无码| 国产成人精品电影在线观看| 国产乱人伦偷精品视频AAA| 精品人妻va出轨中文字幕| 狼色精品人妻在线视频| 久久精品中文闷骚内射| 国产精品天干天干综合网| 69SEX久久精品国产麻豆|