OrchardCore實(shí)現(xiàn)模塊化核心原理分析
【導(dǎo)讀】ABP?vNext并未過(guò)多探究,當(dāng)然其基于DDD理念分層清晰,靈活性、擴(kuò)展性自然也不在話下,但有些情況下我可能會(huì)首選OrchardCore,并非ABP?vNext不可
若改造項(xiàng)目,也因歷史遺留問(wèn)題,數(shù)據(jù)庫(kù)表設(shè)計(jì)也可能存在不合理,此時(shí)從頭開(kāi)始再搭建如此龐大的架子,感覺(jué)會(huì)有點(diǎn)虛空,同時(shí)也要考慮團(tuán)隊(duì)內(nèi)部情況,不是那么容易上手,反而可能會(huì)違背初心,花更多時(shí)間和精力在各種模型理解上
我們完全可以為后續(xù)做鋪墊,先搭建出底層基本設(shè)施,再基于此做靈活擴(kuò)展即可,每個(gè)公司項(xiàng)目具體情況都不一樣,比如倉(cāng)儲(chǔ)模式可能需要結(jié)合項(xiàng)目進(jìn)行對(duì)應(yīng) 改造,倉(cāng)儲(chǔ)只是提供了一種基本思想,若真將網(wǎng)上普遍流傳的模式照搬可能并不是那么好用,可能會(huì)認(rèn)為倉(cāng)儲(chǔ)莫不是一種反模式?
.NET Core模塊化插件
.NET Core內(nèi)置提供了AssemblyLoadContext加載dll插件方式實(shí)現(xiàn)模塊化,然后將其進(jìn)行注冊(cè)
var mvcBuilder = services.AddMvc();foreach (var module in modules){// Register controller from modulesmvcBuilder.AddApplicationPart(module.Assembly);}
這種方式雖可行,在我看來(lái)只能作為一種臨時(shí)解決方案并不利于長(zhǎng)期,因?yàn)樾桀~外創(chuàng)建一個(gè)新的項(xiàng)目,然后加載所生成dll,由于沒(méi)有底層設(shè)施做支撐,所以極易引起版本不一致問(wèn)題,而且手動(dòng)被迫性質(zhì)太強(qiáng),實(shí)現(xiàn)模塊化方案最終的目標(biāo)則只需關(guān)注業(yè)務(wù)邏輯實(shí)現(xiàn),我們來(lái)看看OrchardCore如何實(shí)現(xiàn)模塊化。
OrchardCore模塊化思想
這里我們并不討論和ABP vNext二者誰(shuí)更強(qiáng)大,沒(méi)有任何意義,比如需結(jié)合現(xiàn)有項(xiàng)目情況、項(xiàng)目大小、是否為多租戶、實(shí)施難度等等多方面考慮才能得出基本結(jié)論,而不是一味追求當(dāng)前主流
比如我們只是想實(shí)現(xiàn)模塊化方案,建議選擇OrchardCore來(lái)實(shí)施,因?yàn)楹芎?jiǎn)單,我們可將其剝離為我所用,而后結(jié)合項(xiàng)目情況是否考慮利用ABP vNext來(lái)進(jìn)行分層處理。借鑒核心思想、才能保證一切可在控制范圍內(nèi)
首先我們先從整體上對(duì)OrchardCore做個(gè)認(rèn)識(shí),細(xì)枝末節(jié)暫不考慮:基于ASP.NET Core多租戶模塊化應(yīng)用框架。
?版本管理:無(wú)論是底層設(shè)施、基本框架、模塊都通過(guò)包管理,同時(shí)框架和包版本基本(包管理走框架包版本)可以統(tǒng)一管理(對(duì)于版本升級(jí)很重要)
核心思想:模塊實(shí)現(xiàn)模塊特性,通過(guò)MSBuild構(gòu)建主程序所添加實(shí)現(xiàn)模塊特性的模塊包,底層設(shè)施掃描模塊特性將其注冊(cè)到容器中,當(dāng)然模塊和模塊特性都可進(jìn)行基本信息描述
OrchardCore模塊化原理
整個(gè)項(xiàng)目架構(gòu)如下圖所示

OrchardCore:底層設(shè)施以及可能需要添加的組件(比如本地化、日志、文件存儲(chǔ)、緩存、Lucene等)
OrchardCore.Frameworks:MVC框架
OrchardCore.Modules:模塊化包(比如郵件服務(wù)、后臺(tái)作業(yè)服務(wù)、第三方集成等等)
OrchardCore.Modules.Cms:Cms模塊包
OrchardCore.Themes:主題管理
OrchardCore.Cms.Web:主程序
我以內(nèi)置所提供示例程序給大家講解整個(gè)詳細(xì)流程,而后有需要更細(xì)致了解的童鞋就可以很快上手了,如下示例主程序加載示例模塊,主程序直接采用引用該示例模塊(實(shí)際則是通過(guò)nuget下載該模塊)

正常情況下我們通過(guò)nuget直接下載的是程序包,而OrchardCore對(duì)于入口則是利用MSBuild加載targets文件(其他組件則直接下載對(duì)應(yīng)包),而targets引用對(duì)應(yīng)包,通過(guò)這種中轉(zhuǎn)方式根據(jù)我的理解主要解決了兩個(gè)問(wèn)題,其一則是可以屏蔽底層設(shè)施包(一次性下載),最重要的是通過(guò)targets文件可自動(dòng)添加主程序程序集所加載模塊包特性
是不是感覺(jué)有點(diǎn)懵,那到底是如何加載模塊包特性的呢?來(lái),請(qǐng)看如下圖,我們以實(shí)際操作從頭再來(lái)做一個(gè)完整梳理(注意:為排版美觀,如下都將省略O(shè)rchardCore前綴)

【1】創(chuàng)建Mvc.Web程序,在nuget上下載Application.Mvc.Targets包
【2】創(chuàng)建Mvc.HelloWorld模塊,在nuget上下載引用Module.Targets包
【3】Mvc.Web主程序引用我們所使用的Mvc.HelloWorld模塊
【4】Application.Mvc.Targets包引用Application.Targets(引入底層設(shè)施)和MVC.Core(引入MVC框架)
【5】示例模塊引入模塊包,該包中存在模塊特性(Module類)
【6】Application.Targets包下存在Application.Targets.targets文件,由于主程序引用了該包,添加所引用實(shí)現(xiàn)模塊特性的包程序集信息到主程序集

學(xué)習(xí)OrchardCore的前提一定要基本了解和會(huì)使用MSBuild,這里不詳細(xì)展開(kāi),此時(shí)我們生成解決方案,我們將會(huì)看到主程序集里面將會(huì)自動(dòng)生成所實(shí)現(xiàn)模塊特性的模塊程序集信息

到這里我們已經(jīng)研究完主程序如何識(shí)別模塊包,接下來(lái)則是如何加載模塊包以及對(duì)應(yīng)注冊(cè)服務(wù)信息
OrcharCore核心在于OrchardCore和OrchardCore.Abstractions這兩個(gè)底層設(shè)施包
歸根到底,其底層設(shè)施源碼一部分可能從官方源碼拷貝過(guò)來(lái)(自我猜測(cè)),為實(shí)現(xiàn)多租戶模式,勢(shì)必要構(gòu)建租戶的容器和路由中間件,這中間就涉及在容器中需要維護(hù)每一個(gè)租戶上下文(ShellContext),并且也要跟蹤每個(gè)租戶的狀態(tài)。
ModularTenantContainerMiddleware作為創(chuàng)建租戶容器中間件
ModularTenantRouterMiddleware作為租戶路由中間件
網(wǎng)上資料一大把,此處省略若干字,有任何疑問(wèn)可評(píng)論區(qū)留言,盡力解答
OrchardCore模塊化實(shí)踐
我將核心進(jìn)行了剝離,實(shí)現(xiàn)了模塊化的一個(gè)demo,將多租戶這一塊我也進(jìn)行了去除,只保留了Shell相關(guān)基本概念,實(shí)際情況下,這些都可以去除,基于當(dāng)前請(qǐng)求構(gòu)建Scope,而無(wú)需再額外構(gòu)建ShellScope和上下文等等,考慮好釋放等問(wèn)題就好

示例主程序?yàn)镸odularDemo.Web.Test,模塊為ModularCore.Test,啟動(dòng)主程序訪問(wèn)模塊中接口


