OrchardCore 通過將服務和中間件放在不同的程式集以支持模塊化。各個模塊提供類似於 ConfigureServices 和 Configure 的方法供運行時調用。 ...
一、概述
通常我們會在 Startup
類通過 void ConfigureServices(IServiceCollection services)
配置應用的服務。常見的形如 AddXXX 的方法,實際上調用的都是 IServiceCollection
或直接說是 ServiceCollection
的 AddSingleton 等方法。調用ApplicationBuilder
的 RequestDelegate Build()
方法會調用 IServiceCollection
的擴展方法 BuildServiceProvider
會創建並返回一個 ServiceProvider 對象。
還會在 Startup
類通過 void Configure(IApplicationBuilder app, IHostingEnvironment env)
配置請求管道,在該方法內進行的主要操作是添加中間件。常見的形如 UseMiddleware 或 UseXXX 的方法,實際上調用的都是 IApplicationBuilder
或直接說是 ApplicationBuilder
的 IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
方法,Use 方法並不是馬上將中間件配置入請求管道,而是將“實例化中間件的方式”保存到 ApplicationBuilder 內部一個列表的操作。調用ApplicationBuilder
的 RequestDelegate Build()
方法會實例化中間件並把各個中間件串聯起來。
OrchardCore
通過將服務和中間件放在不同的程式集以支持模塊化。各個模塊提供類似於 ConfigureServices 和 Configure 的方法供運行時調用。
OrchardCore
還支持 Multi-Tenancy
。Tenant
有如下特性:
- 多個 Tenant 運行在同一個應用程式域中,每個 Tenant 幾乎可以看做是獨立的網站;
- 根據 Host 、Port 和 Path 的各種組合匹配不同的 Tenant(ModularTenantContainerMiddleware);
- 延遲激活,第一次請求 Tenant 才會激活(ModularTenantContainerMiddleware);
- 每個 Tenant 有不同的 DI 容器(ModularTenantContainerMiddleware);
- 每個 Tenant 有不同的請求管道,可以共用中間件,還可以使用特定中間件(ModularTenantRouterMiddleware)。
二、模塊定義
模塊是依賴於 OrchardCore.Modules.Targets
程式集的程式集,可以有各自的配置、選項、DI 服務和中間件等,還可以有各自的路由、視圖、控制器、 Filter 和 ModelBinder 等,看起來像是一個 MVC Area
。
模塊包含 0 或多個 Feature
。Feature 是功能的邏輯組合,可單獨開啟或禁用。
Feature 之間可有依賴關係,並且支持跨模塊的依賴。
備註:
OrchardCore 中,一個程式集只包含一個模塊。
模塊可以看做是特殊的 Feature 。
用於定義Theme
的OrchardCore.Theme.Targets
程式集也依賴於OrchardCore.Modules.Targets
程式集。
1、Mainifest.cs 文件
模塊有個以程式集特性的形式嵌入程式集中的 Mainifest
,用於描述模塊的基本信息、擁有的 Feature
和依賴的其他 Feature
等。一般寫在 Mainifest.cs
文件中,比如:
1
|
using OrchardCore.Modules.Manifest;
|
在運行時可將 Mainifest 讀取至 MainifestInfo
對象中。ModuleAttribure
用於描述模塊基本信息,只能用於程式集並且只能使用一次,在運行時可讀取至 ModuleInfo 對象中。
一個模塊可以包含 0 或多個 Feature 。FeatureAttribure
用於描述模塊提供的 Feature,只能用於程式集並且可以使用多次,在運行時可讀取至 FeatureInfo 對象中。
備註:ModuleAttribute 繼承自 FeatureAttribute ,都位於OrchardCore.Abstractions程式集、OrchardCore.Modules.Manifest命名空間中。
從類或對象來看,1 個 MainifestInfo 對象包含1個 ModuleInfo 對象,1 個 ModuleInfo 對象包含 0 或多個 FeatureInfo 對象。
2、ManifestInfo 和 FeatureInfo 類
ExtensionManager類用於獲取 Mainifest ,並將相關數據反序列化入 ManifestInfo 和 FeatureInfo對象中。
3、ModuelNameAttribute 類
如果一個項目引用了一些模塊,MSBuild 在生成項目時會針對每個模塊添加一個程式集級的 ModuleNameAttrbute ,用於保存引用的模塊名稱。
AssemblyAttributeModuleNamesProvider 類的 IEnumerable<string> GetModuleNames()
方法能夠收集到 ModuleNameAttrbute 。
備註:AssemblyAttributeModuleNamesProvider 位於OrchardCore.Abstractions程式集、OrchardCore.Modules命名空間中。
4、ModuleMarkerAttribute 類
MSBuild 在生成模塊的項目時會自動添加程式集級的 ModuleMarkerAttribute 。ModuleMarkerAttribute 繼承 ModuleAttribute),位於OrchardCore.Abstractions程式集、OrchardCore.Modules.Manifest命名空間中
5、ModuleAssetAttribute類
MSBuild 在生成模塊的項目時會自動添加程式集級的 ModuleAssetAttribute。ModuleAssetAttribute繼承 ModuleAttribute),位於OrchardCore.Abstractions程式集、OrchardCore.Modules.Manifest命名空間中
6、Module 類
在創建 Module 對象時,傳入模塊程式集的名稱,構造函數會通過 Assembly.Load 載入模塊程式集,並且收集模塊的 ModuleAttribute、ModuleAssetAttribute 和 ModuleMarkerAttribute 放入自身屬性中。
註意:這裡說的是 Module 類不是 ModuleAttribute 類。
備註:ModularApplicationContext 位於 OrchardCore.Abstractions程式集、OrchardCore.Modules命名空間中。
7、IStartup 介面
每個模塊可能需要註冊一些服務至 DI 容器中,也可能需要註冊一些中間件。OrchardCore 定義了一個 OrchardCore.Modules.IStartup, OrchardCore.Modules.Abstractions
介面,以及實現了該介面的 OrchardCore.Module s.StartupBase, sOrchardCore.Modules.Abstractions
抽象類。OrchardCore 模塊通常有一個 Startup.cs
文件,實現了繼承自 SetupBase
抽象類的名為 Startup
的具體類。
註意:OrchardCore 的
Startup
類不是指通常 ASP.NET Core 中的那個類,IStartup
介面也不是通常 ASP.NET Core 中的那個介面,儘管它們的確很相似。
通常,對於 ASP.NET Core 應用的 Startup 類我們不直接實現 IStartup 介面,而採用更靈活的基於方法名約定的方式。另外,通過 IHostingStartup(承載啟動)實現,在啟動時從外部程式集嚮應用添加增強功能。但是使用 IHostingStartup 無法控制各個模塊註冊服務和添加中間件的順序,也不支持延遲載入。OrchardCore.Modules.IStartup,OrchardCore.Modules.Abstractions
相較於 Microsoft.AspNetCore.Hosting.IStartup,Microsoft.AspNetCore.Hosting.Abstractions
多了個 Order
屬性,並且前者的 Configure 方法簽名為void Configure(IApplicationBuilder app, IRouteBuilder routes, IServiceProvider serviceProvider)
,後者為 void Configure(IApplicationBuilder app)
。因為模塊通常位於不同的程式集, Order 屬性的作用是控制向 DI 容器註冊服務、添加中間件、添加配置和添加路由的順序。
備註:
void Configure(IApplicationBuilder app, IRouteBuilder routes, IServiceProvider serviceProvider)
的 routes 和 serviceProvier 是為了支持模塊化和Multi-Tenancy
。
三、模塊引擎
事實上沒有一種明確的組件叫模塊引擎。OrchardCore 提供了一些由於支持模塊的基礎設施,並提供將分散於各個模塊的服務收集起來註冊至 DI 容器,以及中間件添加至請求管道的機制。
1、AddOrchardCore
AddOrchardCore 不准確地說就是將服務註冊至 DI 容器中以及將中間件添加至請求管道的,並返回一個 OrchardCoreBuilder 對象。
OrchardCoreBuilder 嚴格來說不是生成器模式,它類似於 Startup 類有 ConfigureServices 和 Configure方法。但是當調用這兩類方法時,並不是直接將服務註冊到 DI 容器中或註冊中間件,而是將註冊的方式通過委托保存在集合中(通過 StartupAction )。這樣做的目的是為了將來給每個 Tenant 註冊這些服務和中間件。
1
|
/// <summary>
|
① AddDefaultServices
添加預設服務,比如 Logging、Localization 和 Web Encoders (Web Encoders 是指 Html、Url 和 Javascript 的編碼器)。
重要的是添加 Routing 服務。IServiceCollection 的擴展方法 AddMvc/AddMvcCore 會添加 Routing 服務。就算不是 MVC 應用也可以是使用路由,並且 OrchardCore 的路由可配置在不同的模塊,所以在這裡註冊是因為後續會使用 Routing 相關服務。
② AddShellServices
添加用於支持 Tenant 的相關服務。Shell 涉及眾多的類,這裡暫時不分析。
③ AddExtensionServices
添加用於支持模塊化的相關服務。主要是 AssemblyAttributeModuleNamesProvider : IModuleNamesProvider
和 ModularApplicationContext : IApplicationContext
。
AssemblyAttributeModuleNamesProvider 提供了一種從程式集的 Attribute 獲取模塊名稱的方式。
ModularApplicationContext 提供了一個 OrchardCore.Modules.Application
對象,可在某些情況下指代應用。使用 ModularApplicationContext 的屬性 Application 時,會觸發 Application 對象的構造過程。
④ AddStaticFiles
添加靜態文件服務中間件,主要是增加 ModuleEmbeddedStaticFileProvider 的支持。
⑤ AddAntiForgery
主要是提供對 Multi-Tenancy 的支持。為不同的 Tenant 的 Antiforgery Cookie 設置的名稱和路徑。
⑥ AddAuthentication
主要是提供對 Multi-Tenancy 的支持。
⑦ AddDataProtection
主要是提供對 Multi-Tenancy 的支持。
2、AddMvc
AddMvc 主要作用是添加和 Mvc 相關的中間件。請註意這是 OrchardBuilder 而不是 IServiceCollection 的擴展方法。
類似的方法 AddNancy 用於提供對 Nancy 的支持。
3、UseOrchardCore
UseOrchardCore
是一個 IApplicationBuilder
的擴展方法,主要作用是添加中間件 ModularTenantContainerMiddleware 和 ModularTenantRouterMiddleware 。
1
|
namespace Microsoft.AspNetCore.Builder
|
四、Multi-Tenancy
在 ModularTenantContainerMiddleware 中間件中,根據 Host 、Port 和 Path 的各種組合匹配不同的 Tenant 。Tenant 的激活延遲性的,在第一次請求 Tenant 才會激活。每個 Tenant 可以有不同的 DI 容器。
在 ModularTenantRouterMiddleware 中間件中,為當前 Tenant 配置單獨的請求管道。
五、服務和中間件註冊點
總結一下目前為止遇見的服務和中間件註冊點。
1、服務註冊點
包含名為 ConfigureServices 或類似的方法的介面和類:
類/介面 | 程式集 | 命名空間 | 備註 |
---|---|---|---|
IStartup | Microsoft.AspNetCore.Hosting.Abstractions | Microsoft.AspNetCore.Hosting | 介面。 |
IStartup | Microsoft.AspNetCore.Hosting.Abstractions | Microsoft.AspNetCore.Hosting | 介面。 |
Startup | 自定義 | 自定義 | 定義於應用。不繼承任何介面或類,實現 Configure 和 ConfigureServices 等方法。 |
IWebHostBuilder | Microsoft.AspNetCore.Hosting.Abstractions | 介面。 | |
WebHostBuilder : IWebHostBuilder | Microsoft.AspNetCore.Hosting | Microsoft.AspNetCore.Hosting | ConfigureServices 不會進行實際的服務註冊操作,當調用 Build 方法時才註冊。 |
IStartup | OrchardCore.Modules.Abstractions | OrchardCore.Modules | 介面。 |
StartupBase: IStartup | OrchardCore.Modules.Abstractions | OrchardCore.Modules | 抽象類。 |
Startup: SetupBase | 自定義 | 自定義 | 定義於 OrchareCore 模塊。 |
OrchardCoreBuilder | OrchardCore .Modules.Abstractions | Microsoft.Extensions.DependencyInjection | 註冊 Tenant 服務和中間件。 |
StartupActions | OrchardCore.Modules.Abstractions | Microsoft.Extensions.DependencyInjection | 包含 ConfigureServicesActions 屬性,而非方法。 |
2、中間件註冊點
包含名為 Configure 或類似方法的介面和類:
類/介面 | 程式集 | 命名空間 | 備註 |
---|---|---|---|
IStartup | Microsoft.AspNetCore.Hosting.Abstractions | Microsoft.AspNetCore.Hosting | 介面。 |
IHostingStartup | Microsoft.AspNetCore.Hosting.Abstractions | Microsoft.AspNetCore.Hosting | 介面。 |
HostingStartup:IHostingStartup | 自定義 | 自定義 | 定義於應用。 |
Startup | 自定義 | 自定義 | 定義於應用。不繼承任何介面或類,實現 Configure 和 ConfigureServices 等方法。 |
IWebHostBuilder | Microsoft.AspNetCore.Hosting.Abstractions | 介面。 | |
WebHostBuilder : IWebHostBuilder | Microsoft.AspNetCore.Hosting | Microsoft.AspNetCore.Hosting | Configure 不會進行實際的添加註冊操作,當調用 Build 方法時才註冊。 |
IStartup | OrchardCore.Modules.Abstractions | OrchardCore.Modules | 介面。 |
StartupBase: IStartup | OrchardCore.Modules.Abstractions | OrchardCore.Modules | 抽象類。 |
Startup: SetupBase | 自定義 | 自定義 | 定義於 OrchareCore 模塊。 |
OrchardCoreBuilder | OrchardCore .Modules.Abstractions | Microsoft.Extensions.DependencyInjection | 註冊 Tenant 服務和中間件。 |
StartupActions | OrchardCore.Modules.Abstractions | Microsoft.Extensions.DependencyInjection | 包含 ConfigureActions 屬性,而非方法。 |
IStartupFilter | Microsoft.AspNetCore.Hosting.Abstractions | Microsoft.AspNetCore.Hosting | 定義於應用或 OrchareCore 模塊。需註冊為服務。 |
參考資料
https://orchardcore.readthedocs.io/en/latest/
http://docs.orchardproject.net/en/latest/
https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/startup?view=aspnetcore-2.1
https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/host/platform-specific-configuration?view=aspnetcore-2.1
https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/host/web-host?view=aspnetcore-2.1