.NET Conf 2020 - 基于ASP.NET Core构建可热插拔的插件化系统
文章標題:.NET Conf 2020 - 基于ASP.NET Core構建可熱插拔的插件化系統
作者:Lamond Lu
項目地址:https://github.com/lamondlu/CoolCat
博客:http://www.cnblogs.com/lwqlun
以下是2020.12.19日的演講文稿和視頻:
大家好,我是陸楠,我來自北京盛安德科技發展有限公司青島分公司,很高興能參加本次.NET開發者大會,今天我分享的主題是《基于ASP.NET Core構建可熱插拔的插件化系統》。
插件化架構,又稱微核架構,指的是軟件的內核相對較小,主要功能和業務邏輯都通過插件實現的架構。
插件化架構一般有兩個核心概念:
內核
插件
內核通常只包含系統運行的最小功能,以及定義插件必須符合的接口;插件則是互相獨立的模塊,一般只包含單一的功能。
插件化技術并不是一個新興的技術,早期很多基于COM開發的WIN32程序其實都是插件化的系統。在.NET/.NET Core中,也有許多插件化的實現方案,例如,開源框架ABP, 開源的內容管理系統DotNetNuke, 電子商務框架NopCommerce。
在設計插件化方案的時候,我們需要考慮以下幾個問題:
如何隔離插件
如何實現插件之間的通訊
如何實現熱插拔
在.NET Framework時代,我們最常用的方案是使用AppDomain應用程序域來封裝插件。使用AppDomain, 我們可以將不同的插件隔離在不同的應用程序域中。至于插件與插件之間的通訊,我們可以借助MarshalByRefObject類來實現。至于熱插拔,我們可以通過AppDomain自帶的Load/Unload方法來完成,非常的簡單。
但是到了.NET Core中,情況大不相同了。主要的原因是.NET Core中已經將AppDomain的概念移除了,那么我們該如何實現插件化呢?
這里我們首先要介紹的是ASP.NET Core中新引入的功能AssemblyLoadContext, 簡稱ALC, ALC提供了一個類似AppDomain的隔離區域,你可以通過ALC來加載程序集,每個ALC加載的程序集之間互不干擾。
這里請注意,正是由于這種設計,如果將一個程序集引入到兩個不同ALC中,運行時會認為他們是不同的程序集。
除了自定義的ALC, 在每個ASP.NET Core應用啟動的時候,運行時都會創建一個默認的ALC, 這里我們需要了解自定義ALC和默認ALC的加載順序
當自定義ALC中的某個插件使用某個程序集的時候,會優先查找當前插件所在的自定義的ALC,如果找不到該程序集,則會進一步查找默認ALC, 所以ALC的程序集加載會優先于默認ALC
我們前面說過,不同的ALC應用相同的程序集,運行時會認為他們是不同的程序集,所以當兩個插件使用相同程序集的,我們最好將這個程序集加載到默認ALC中,否則在插件交互的時候可能會出現類型沖突。
除了AssemblyLoadContext, 為了實現插件化,微軟在ASP.NET Core中還提供了另外一個高級特性Application Part - 應用組件。
Application Part并不算一個新特性,因為在它在.NET Core 2.x版本中就已經被引入了,但是可能部分開發人員沒有過或了解過它。Application Part為ASP.NET Core提供了強大的復用能力,使用Application Part, ASP.NET Core可以從程序集中發現控制器、視圖組件、Razor預編譯視圖、Tag Helper等功能,再借助Application Part Manager, 這些已經編譯好的功能組件就可以在其它項目中直接復用了,這就極大提高了ASP.NET Core功能組件的可復用行。
基于AssemblyLoadContext和Application Part, 你就可以輕松的實現ASP.NET Core的插件化了,但是如果想要在ASP.NET Core中實現一個可熱插拔的插件化組件系統,我們還需要針對ASP.NET Core解決很多適配性問題,例如:
如果在運行時加載預編譯視圖?
如果在運行時刷新路由和Controler/Action的映射關系?
一個組件如何從另外一個組件拉取數據
一個組件如何向另外一個組件發送消息通知,完成進一步的業務操作
為了簡化這一部分的復雜度,我搭建了一個開源項目CoolCat, CoolCat默認支持.NET Core 3.1和.NET 5。
CoolCat已經實現了以下的特性
插件的安裝升級
運行時熱插拔插件
插件間通訊
類Swagger的插件文檔
支持容器化
以下是CoolCat的整體架構圖:
這里主程序為CoolCat, 所有的插件都通過ALC加載到主程序中,主程序中定義了通知中心、文檔中心、查詢中心
通知中心負責跨插件的消息通知
文檔中心負責生成插件的文檔
查詢中心負責跨插件的數據查詢
并且為了簡化創建插件項目,我創建了一個CoolCat插件模板,你可以通過dotnet new命令來安裝插件模板,并安裝模板項目。
dotnet?new?–i?CoolCatModule dotnet?new?CoolCatModule?–n?{projectName}這里創建出的插件項目和一個普通MVC項目相差無幾,比較特殊的是項目會自動生成一個plugin.json文件,里面包含了當前插件的基本信息。
如果這個項目的生成文件打包,那么它就是一個可移動的插件安裝包了。
下面呢,我們就通過一個簡單的Demo, 給大家演示一下CoolCat項目的基本功能。
這里我們首先使用dotnet run命令啟動當前CoolCat, 當程序第一次啟動的時候,會自動建表。這里呢,我使用了FluentMigrator作為數據庫遷移工具,所以在項目啟動時,可以進行自動的腳本遷移。
項目啟動之后,我們就可以從瀏覽器打開這個項目了。項目的默認界面是安裝界面,我們可以在這個界面上選擇一些預定義的插件,完成安裝
當然也不僅限于此,如果你想自定義一個其他的預安裝插件,你可以將這些插件放置在項目下的PresetModules目錄中。
這里呢,我們就選擇默認的2個插件,完成安裝。
安裝完成之后,我們就會自動進入CoolCat的主界面。這里我們可以通過System菜單下的Plugins子菜單來管理插件。
現在呢,我們來模擬一個場景,假設我們當前開發了2個插件,一個是圖書庫存插件,一個是圖書租借插件。租借插件的數據來源是庫存插件。并且當某本圖書從租借插件租出之后,庫存插件中的當前圖書的狀態也應該變為出庫狀態。
這里我們首先通過CoolCat來安裝這2個插件。安裝完成之后,我們啟用插件,這里大家會發現,當我們啟動插件之后,頂部導航欄中會自動出現這個插件的菜單,這說明我們的熱插拔功能正確的引導并加載的插件。
下一步,我們進入庫存插件,添加一本圖書C#, 添加完成之后,我們會發現這本書的默認狀態是入庫狀態。
現在我們打開圖書租借功能,我們會發現入庫狀態的圖書,正確的顯示在了可租借圖書列表界面,這說明我們的跨插件拉取數據成功。
這時候,我們選擇租出這本書,點擊Rent按鈕,操作完成之后,這本書就從可租借列表中消失了。
下面我們回到圖書庫存插件,你會發現圖書庫存的狀態已經變為出庫,這是說明我們的跨插件消息傳輸成功了,當圖書租出之后,后續的出庫操作自動完成。
至此,我們就完成了這個簡單的Demo
如果大家感興趣的話,可以下載CoolCat項目自行體驗一下,針對整個框架的研究過程和其中遇到的問題,我都寫在了我的博客園站點中,大家可以自行查看。如果遇到問題或者想參與到本項目中,可以給我發郵件,也可以在博客園給我留言。
以上就是我今天分享的全部內容,謝謝大家。
總結
以上是生活随笔為你收集整理的.NET Conf 2020 - 基于ASP.NET Core构建可热插拔的插件化系统的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .NET 云原生架构师训练营(模块二 基
- 下一篇: 多款主流编程语言,哪款开发软件最安全?