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

     用過和作過插件的都會了解插件的好處,園子裏也有不少和討論,但大都只些簡單的加載程序集什麼的,這裏主要討論的就是使用 ASP.NET MVC 4 來實現每一個插件均可以徹底從主站點剝離出來,即便只是一個插件,也是一個完整的站點,同時也能夠和其它插件一塊兒組裝成一個龐大的系統。html

參考資料:前端

ASP.NET MVC 4 源碼。架構

Orchard 源碼。併發

MVC3PlugInDemo 源碼。mvc

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-modelide

首先,很是感謝以上幾位大牛分享的文章,因爲文筆很差,對.NET 瞭解也不夠,但願你們多多指點。模塊化

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

最終結構圖以下。ui

 

當把插件的站點發布出來後,目錄名爲插件名,並將該目錄及目錄下的全部文件複製到Plugins目錄下便可自動安裝並運行,不須要重啓程序池。google

 

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

 

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

問題產生緣由:

.NET 會把.cshtml 與相關的程序集進行編譯,以後訪問的是編譯後的臨時程序集,可是,因爲沒有引用進入系統中,這裏編譯的時候沒有該程序集,就會出現錯誤。

那麼,要解決這個問題,就須要在編譯時,把須要的程序集,都一塊兒編譯了,可是,怎麼樣才能夠實現?

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

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

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

BuildManager.AddReferencedAssembly(assembly);

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

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

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

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

在調試階段下,只有從新生成的代碼時能夠正常運行,從新生成以後的代碼,在點啓動調試時,就會出現編譯錯誤問題,調試發現,在這個時候,系統並無將須要的程序集加載到系統中,有大牛瞭解的話但願指點下緣由。

可是,在使用了Web.config 配置文件中的節點「probing」之後,把相關的程序集複製到「probing」指定的目錄下,就能正常運行了。

可是, 因爲上面的那段代碼只能夠在預啓動階段使用,全部註定了該方法有個缺點,就是每一個更新插件時,都要重啓或者回收一次程序池,沒能正常的作到插件化的靈活性。

 

二、在模板(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 插件化架構簡單實現-實例篇

相關文章
相關標籤/搜索