ASP.NET MVC 4 插件化架構簡單實現-思路篇


     用過和做過插件的都會了解插件的好處,園子里也有很多和討論,但大都只些簡單的加載程序集什么的,這里主要討論的就是使用 ASP.NET MVC 4 來實現每個插件都可以完全從主站點剝離出來,即使只是一個插件,也是一個完整的站點,同時也可以和其它插件一起組裝成一個龐大的系統。

參考資料:

ASP.NET MVC 4 源碼。

Orchard 源碼。

MVC3PlugInDemo 源碼。

ASP.NET MVC的Razor引擎:View編譯原理

基於ASP.NET MVC3 Razor的模塊化/插件式架構實現

基於OSGi.NET開發ASP.NET MVC 3.0插件化應用程序

http://stackoverflow.com/questions/6923572/asp-net-mvc-3-portable-area-view-doesnt-find-my-model

首先,非常感謝以上幾位大牛分享的文章,由於文筆不好,對.NET 了解也不夠,希望大家多多指點。

理想情況下是希望能夠像Orchard那樣,可以運行時修改代碼,又或者可以直接把插件(包含頁面、樣式、圖片等資源文件)編譯成一個DLL來使用(但是這樣的做法會對前端與美工修改不便,而且就算改一個字也要重新編譯一個DLL),只是依然還沒找到方法ORZ。

最終結構圖如下。

 

當把插件的站點發布出來后,目錄名為插件名,並將該目錄及目錄下的所有文件復制到Plugins目錄下即可自動安裝並運行,不需要重啟程序池。

 

要實現這么一個架構,最初認為,只要使用 Assembly.LoadFile(name);方法來加載外部的程序集,並且使用反射創建控制器,在定義一下MVC的模板引擎的搜索路徑不就可以了嗎?

 

當具體實現之后,發現,在不使用強類型的模型綁定時,可以正常使用,但是,使用了強類型的模型綁定時,則會出現以下錯誤。

問題產生原因:

.NET 會把.cshtml 與相關的程序集進行編譯,之后訪問的是編譯后的臨時程序集,但是,由於沒有引用進入系統中,這里編譯的時候沒有該程序集,就會出現錯誤。

那么,要解決這個問題,就需要在編譯時,把需要的程序集,都一起編譯了,但是,怎么樣才可以實現?

直接引用並使用類庫的時候,系統會自行編譯到一起了,所以解決辦法有兩種:

1、在系統啟動前的預編譯時,手動把相關的程序集增加進系統中,這樣就是一個實際存在於系統的程序集,在頁面編譯時自然會編譯進去。

在google查找相關的解決方法時,發現了該方法:

BuildManager.AddReferencedAssembly(assembly);

在查MSDN有這么一段話:此方法必須在 Global.asax 文件中的 Application_Start 事件發生前調用。

也就意味着加載程序集的方法就必須要在預啟動階段就是加載了。

並且使用上面的方法,來把程序集加到系統里。

雖然這樣可以正常使用了,但是,偶爾還是會有出現編譯錯誤的異常。

在調試階段下,只有重新生成的代碼時可以正常運行,重新生成之后的代碼,在點啟動調試時,就會出現編譯錯誤問題,調試發現,在這個時候,系統並沒有將需要的程序集加載到系統中,有大牛了解的話希望指點下原因。

但是,在使用了Web.config 配置文件中的節點“probing”以后,把相關的程序集復制到“probing”指定的目錄下,就能正常運行了。

但是, 由於上面的那段代碼只可以在預啟動階段使用,所有注定了該方法有個缺點,就是每個更新插件時,都要重啟或者回收一次程序池,沒能正常的做到插件化的靈活性。

 

2、在模板(cshtml)進行編譯前,把外部引用的相關的程序集增加到編譯信息中,這樣在對模板進行編譯的同時,會把該程序集也編譯進去。

 在谷歌娘的幫助下,找到了該事件:

RazorBuildProvider.CodeGenerationStarted

從名字可以看出,這是在編譯啟動時觸發的事件,具體功能不明ORZ。

可以通過該事件,把外部的程序集增加到 RazorBuildProvider 類中。

provider.AssemblyBuilder.AddAssemblyReference(plugin.Assembly);

provider 是 RazorBuildProvider 類的一個實例。
plugin.Assembly 是一個頁面所使用的程序集。
只要把這段代碼放到模板引擎的搜索視圖的位置,即可根據需要,將增加外部的程序集,由於重復增加會出現已添加組件異常,所以,這里加了個 isLoadAssembly 變量來確認是否已增加過。

 

        /// <summary>
        /// 給運行時編譯的頁面加了引用程序集。
        /// </summary>
        /// <param name="pluginName"></param>
        private void CodeGeneration(string pluginName)
        {
            RazorBuildProvider.CodeGenerationStarted += (object sender, EventArgs e) =>
            {
                RazorBuildProvider provider = (RazorBuildProvider)sender;

                var plugin = PluginManager.GetPlugin(pluginName);

                if (plugin != null)
                {
                    provider.AssemblyBuilder.AddAssemblyReference(plugin.Assembly);
                }
            };
        }

 

 

 

我不喜歡每裝一個插件,都要重啟一次,所以我選擇使用了第二種方法。

下一篇,將使用第二種方法來進行具體的實踐並發布源碼。

ASP.NET MVC 4 插件化架構簡單實現-思路篇

ASP.NET MVC 4 插件化架構簡單實現-實例篇


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM