一、概述

通常我们会在 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-TenancyTenant 有如下特性:

  1. 多个 Tenant 运行在同一个应用程序域中,每个 Tenant 几乎可以看做是独立的网站;

  2. 根据 Host 、Port 和 Path 的各种组合匹配不同的 Tenant(ModularTenantContainerMiddleware);

  3. 延迟激活,第一次请求 Tenant 才会激活(ModularTenantContainerMiddleware);

  4. 每个 Tenant 有不同的 DI 容器(ModularTenantContainerMiddleware);

  5. 每个 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 文件中,比如:

using OrchardCore.Modules.Manifest;[assembly: Module(Name = "XML-RPC",Author = "The Orchard Team",Website = "http://orchardproject.net",Version = "2.0.0")][assembly: Feature(Id = "OrchardCore.XmlRpc",Name = "XML-RPC",Description = "The XML-RPC module enables creation of contents from client applications such as Open Live Writer.",Category = "Infrastructure")][assembly: Feature(Id = "OrchardCore.RemotePublishing",Name = "Remote Publishing",Description = "The remote publishing feature enables creation of contents from client applications such as Open Live Writer.",Dependencies = new [] { "OrchardCore.XmlRpc" },Category = "Infrastructure")]

在运行时可将 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 注册这些服务和中间件。

/// <summary>/// Adds OrchardCore services to the host service collection./// </summary>public static OrchardCoreBuilder AddOrchardCore(this IServiceCollection services){// If an instance of OrchardCoreBuilder exists reuse it,// so we can call AddOrchardCore several times.var builder = services.LastOrDefault(d => d.ServiceType == typeof(OrchardCoreBuilder))?.ImplementationInstance as OrchardCoreBuilder;if (builder == null){builder = new OrchardCoreBuilder(services);services.AddSingleton(builder);AddDefaultServices(services);AddShellServices(services);AddExtensionServices(builder);AddStaticFiles(builder);AddAntiForgery(builder);AddAuthentication(builder);AddDataProtection(builder);// Register the list of services to be resolved later onservices.AddSingleton(services);}return builder;}

① 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 。

namespace Microsoft.AspNetCore.Builder{public static class ApplicationBuilderExtensions{/// <summary>/// Enables multi-tenant requests support for the current path./// </summary>public static IApplicationBuilder UseOrchardCore(this IApplicationBuilder app, Action<IApplicationBuilder> configure = null){var env = app.ApplicationServices.GetRequiredService<IHostingEnvironment>();var appContext = app.ApplicationServices.GetRequiredService<IApplicationContext>();env.ContentRootFileProvider = new CompositeFileProvider(new ModuleEmbeddedFileProvider(appContext),env.ContentRootFileProvider);app.UseMiddleware<PoweredByMiddleware>();// Ensure the shell tenants are loaded when a request comes in// and replaces the current service provider for the tenant's one.app.UseMiddleware<ModularTenantContainerMiddleware>();configure?.Invoke(app);app.UseMiddleware<ModularTenantRouterMiddleware>();return app;}}}

四、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

原文地址: https://www.cnblogs.com/alby/p/orchardcore-modular-and-multi-tenancy.html



.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

OrchardCore 如何实现模块化( Modular )和 Multi-Tenancy相关推荐

  1. Pulsar官方文档翻译-概念和架构-多租户(Multi Tenancy)

    官网原文标题<Multi Tenancy> 翻译时间:2018-10-28 官网原文地址:http://pulsar.apache.org/docs/en/concepts-multi-t ...

  2. Pulsar Multi Tenancy 多租户

    目录 1.Tenants 租户 2.Namespaces 命名空间 3.命名空间更改记录方案和主题级策略 Pulsar 从一开始就是一个多租户系统.为了支持多个租户(multi-tenancy),Pu ...

  3. OrchardCore实现模块化核心原理分析

    [导读]ABP vNext并未过多探究,当然其基于DDD理念分层清晰,灵活性.扩展性自然也不在话下,但有些情况下我可能会首选OrchardCore,并非ABP vNext不可 若改造项目,也因历史遗留 ...

  4. 组件化、模块化、集中式、分布式、服务化、面向服务的架构、微服务架构

    组件化.模块化.集中式.分布式.服务化.面向服务的架构.微服务架构 最近最火的词是什么?那大概就是微服务(Microservice)了.最近也火的一踏糊涂的Docker.DevOps也都是围绕着微服务 ...

  5. BlackArch-Tools

    BlackArch-Tools 简介安装在ArchLinux之上添加存储库从blackarch存储库安装工具替代安装方法BlackArch Linux Complete Tools List 简介 B ...

  6. 东北黑土区不同纬度农田土壤真菌分子生态网络的比较

    文章目录 东北黑土区不同纬度农田土壤真菌分子生态网络的比较 摘 要 背景 1材料与方法 1.1土壤样品采集 1.2土壤总DNA提取和Illumina MiSeq测序 1.3分子生态网络构建 1.4数据 ...

  7. 需求编写的几点经验之谈

    关键字:CMMI 需求管理 软件测试         近年来,"需求管理"正成为中国当前工程应用和商业热域的热点.目前,有关需求管理的实践大量应用于软件开发工程等领域,软件开发团队 ...

  8. 深入理解JVM文章合集

    原文地址:http://ddrv.cn/a/88331 Java动态追踪技术探究 在Java虚拟机中,字符串常量到底存放在哪 一次生产 CPU 100% 排查优化实践 聊聊 Java 虚拟机:类的加载 ...

  9. 基于.NET Core的优秀开源项目合集

    开源项目非常适合入门,并且可以作为体系结构参考的好资源, GitHub中有几个开源的.NET Core项目,这些项目将帮助您使用不同类型的体系结构和编码模式来深入学习 .NET Core技术, 本文列 ...

最新文章

  1. torchtext语料库 词与 下标互转使用教程
  2. Vivado IP核生成设置
  3. 中文乱码各个浏览器的处理
  4. JS实现一键分享功能
  5. 关于程序工作者的规划与思考
  6. VMware 7.1.4安装Mac.OS.X.Lion.操作系统 key:安装 系统
  7. 让你页面速度飞起来 Web前端性能优化
  8. onpagefinished等了很久才执行_互联网职业经理人的素养(二):执行力
  9. 指针数组、数组指针、指针函数、函数指针
  10. linux配置内存buffer,调整Linux的网络栈(Buffer Size)来提升网络性能
  11. c语言命名规则 [转载]
  12. fontForge开源字体定制工具
  13. BBU+RRU基本介绍
  14. 短信验证码是什么?短信验证码是什么意思
  15. 对抗攻击常见方法汇总
  16. 2020大疆校招B卷第三题
  17. 过零检测法MATLAB仿真,过零检测 - MATLAB Simulink - MathWorks 中国
  18. 交换机接口及连接技巧
  19. pandas中drop用法_机器学习笔记:Pandas的delete、drop函数的用法
  20. 关于电脑设置个性化此电脑属性打不开问题

热门文章

  1. 动态切换父元素隐藏和显示里面的子元素的动画会再一次执行吗?
  2. 2016年工作总结和计划
  3. 一次面试引发的思考(中小型网站优化思考) (转)
  4. Primes on Interval
  5. PHP环境,放置系统盘的文件
  6. Kubernetes:实现应用不停机更新
  7. 如何在 ASP.NET CORE 中获取客户端 IP ?
  8. Dapr + .NET Core实战(二) 服务调用
  9. .Net之Swagger基础使用
  10. dotNet Core 3.1 使用 Aspose (部署 Docker)