ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Orchard Core 配置体系深度解析:IShellConfiguration 与多租户配置实战

Orchard Core 配置体系深度解析:IShellConfiguration 与多租户配置实战 CMS后端Web框架【免费下载链接】OrchardCoreOrchard Core is an open-source modular and multi-tenant application framework built with ASP.NET Core, and a content management system (CMS) built on top of that framework.项目地址https://gitcode.com/gh_mirrors/or/OrchardCore点击查看免费下载Orchard Core 在 ASP.NET Core 标准IConfiguration之上扩展出IShellConfiguration使每个租户Tenant都能拥有叠加在全局配置之上的独立配置层。本文以OrchardCore.Cms.Web启动项目为示例系统讲解配置源的组织方式、加载顺序、租户预配置与共享数据库配置、IOptions/IOptionsMonitor代码级配置以及ORCHARD_APP_DATA等实战要点帮助你在自己的 Orchard Core 应用无论是源码项目还是 NuGet 包引用的 Web 应用中正确落地多租户配置。背景从IConfiguration到IShellConfigurationOrchard Core 的配置体系完全构建在 ASP.NET Core 配置框架之上。ASP.NET Core 的IConfiguration提供了统一的键值配置抽象支持多种配置源JSON 文件、环境变量、命令行参数、用户机密等按顺序叠加后加载的同名键覆盖先加载的值。Orchard Core 在此基础上定义了租户级配置接口public interface IShellConfiguration : IConfiguration;该接口定义位于 src/OrchardCore/OrchardCore.Abstractions/Shell/Configuration/IShellConfiguration.cs它直接继承自IConfiguration语义上表示当前租户 Shell 的配置。其默认实现ShellConfiguration位于 src/OrchardCore/OrchardCore.Abstractions/Shell/Configuration/ShellConfiguration.cs从源码注释可以确认它的构建链路持有租户的IConfiguration惰性构建lazily built数据来源依次为应用配置appsettings.json、App_Data/appsettings.json文件、App_Data/Sites/{tenant}/appsettings.json文件。ShellConfiguration在实现上还有一个值得注意的细节其索引器在按原始键读取失败时会把键中的下划线_替换为点.再读一次。也就是说读取OrchardCore_Media:MaxFileSize与OrchardCore.Media:MaxFileSize时都能命中同一份配置这正是文档中OrchardCore.Media仅为向后兼容应迁移到下划线_写法的底层原因。配置源Configuration Sources开发者并不局限于单一配置源。Orchard Core 允许把多种配置源组合使用默认配置可以被来自另一配置源的设置覆盖前提是键存在。这些配置源按 配置源加载顺序 一节描述的顺序加载。注意下文appsettings.json示例中展示的IShellConfiguration写法只对明确支持此类配置的模块生效。使用前请查阅对应模块的代码或文档确认支持情况。启动项目中的IShellConfigurationOrchardCore段在启动项目如 OrchardCore.Cms.Web.csproj的appsettings.json中Orchard Core 将全部配置数据存放在OrchardCore段之下{ OrchardCore: { // 模块配置 } }每个 Orchard Core 模块在OrchardCore段下拥有自己的配置子段命名规则为模块名以下划线分隔{ OrchardCore: { OrchardCore_Media: { // 该模块的单独配置 } } }实际可参考仓库自带的 src/OrchardCore.Cms.Web/appsettings.json其中以注释形式给出了大量模块配置示例例如OrchardCore_MediaMaxFileSize、AllowedFileExtensions、CdnBaseUrl、AssetsRequestPath等媒体配置OrchardCore_ResourcesResourceDebugMode、UseCdn、CdnBaseUrl、AppendVersion等资源CDN配置OrchardCore_AdminAdminUrlPrefix自定义管理后台前缀OrchardCore_TenantsTenantRemovalAllowed、RequireTablePrefix、TablePrefixPattern、SchemaPattern等租户级数据库配置。需要说明的是本文以OrchardCore.Cms.Web为例如果你通过 NuGet 包在自己的 Web 应用中引用 Orchard相同的配置方式在你的 Web 应用项目里同样适用。租户预配置Tenant Pre-configuration在租户被创建之前可以预先为其填充 Setup初始化安装阶段的配置值在OrchardCore段下指定以租户名称命名的节并带上State值为Uninitialized{ OrchardCore: { MyTenant: { State: Uninitialized, RequestUrlPrefix: mytenant, ConnectionString: ..., DatabaseProvider: SqlConnection } } }配置完成后该租户会出现在管理后台的Tenants租户列表中并且在执行 Setup 时直接采用这些预配置值例如RequestUrlPrefix决定访问路径前缀DatabaseProvider/ConnectionString决定数据库引擎与连接串。租户后配置Tenant Post-configuration对已经创建完成的租户可以在OrchardCore段下指定以租户名称命名的节来覆盖其配置此时不需要提供State值{ OrchardCore: { Default: { OrchardCore_Media: { // 针对该租户的特定配置 } } } }这里的Default是默认租户的名字你也可以替换成任意已存在的租户名。全局租户数据访问配置让所有租户共享一个数据库如果希望所有租户访问同一个数据库可以在单一位置集中配置而不必为每个租户逐一手动填写相同的连接字符串{ OrchardCore: { ConnectionString: ..., DatabaseProvider: SqlConnection, OrchardCore_Tenants: { RequireTablePrefix: true, TablePrefixPattern: {{ ShellSettings.Name }}, SchemaPattern: dbo }, Default : { State: Uninitialized, TablePrefix: Default } } }针对上述配置有几点关键说明与前文租户配置不同的是这里的配置键位于OrchardCore段的根级对所有租户生效ConnectionString为所有租户共享的数据库连接串DatabaseProvider应取值为实际的数据库引擎示例为 SQL Server 的SqlConnectionDefault:TablePrefix配置的是 Default 租户自身的表前缀用于把它的数据表与共享库中其他租户的数据表隔离。它不会自动为之后通过后台或 API 创建的租户填充或强制前缀仅凭它也不会锁定或隐藏其他租户的数据库提供程序与连接设置OrchardCore_Tenants:RequireTablePrefix开启后在创建新租户、或编辑未初始化租户时若其使用的数据库提供程序支持表前缀则强制要求填写表前缀对于需要连接字符串的提供程序Orchard 仅在DatabaseProvider与ConnectionString同时配置时才把根级数据库配置视为预设值。只设置DatabaseProvider不会锁定 Setup 或租户数据库字段也不会为 Setup Shell 引导 YesSqlOrchardCore_Tenants:TablePrefixPattern用于自动生成每个租户的TablePrefix后台与 API 不再需要手动输入。模式使用 Fluid 语法作用域内可访问ShellSettings例如{{ ShellSettings.Name }}OrchardCore_Tenants:SchemaPattern对租户的Schema采用相同机制例如dbo或{{ ShellSettings.Name }}无论模式生成还是手动输入TablePrefix与Schema都会作为 SQL 标识符进行校验只能使用字母、数字和下划线且必须以字母或下划线开头一旦配置了模式租户创建、编辑未初始化租户以及租户 Setup 时Orchard 都会使用生成值而不是提交的手动值这种共享数据库模式适用于 SQL Server、MySQL、PostgreSQL 等提供程序。内置的 SQLite 提供程序不使用根级ConnectionString来存放租户数据也不能通过该模式配置为单个共享.db文件 每租户前缀的方式。这样的设计让应用可以方便地在不同环境如预发布与生产之间迁移只需在对应环境的配置中修改数据库设置即可。租户的 Shell 设置中不会包含这些信息所有租户统一使用这份全局配置。仓库自带的 src/OrchardCore.Cms.Web/appsettings.json 中对OrchardCore_Tenants也给出了同样的默认值注释TablePrefixPattern默认值为{{ ShellSettings.Name }}SchemaPattern默认值为dbo仅对支持相应特性的数据库提供程序生效。与此相关的话题是 Shells 配置提供程序特别是其中的 Database Shells Configuration Provider 章节讲解了如何把全部 Shell 配置存放到数据库中。通过IOptions进行代码级配置除了配置文件你还可以在 Web 项目Startup类中通过代码配置IOptions详见 ASP.NET Core 官方 Options 模式文档。Orchard Core 的许多功能既可以在管理后台通过存储在数据库中的站点设置Site Settings来配置也暴露了基于IOptions的配置入口。如果你希望覆盖站点设置或默认设置可以编写自己的配置代码。例如Resource 模块允许通过ResourceOptions类配置 CDN默认情况下该类从给定租户的站点设置即后台设置的值填充。但你可以在Startup类中覆盖站点设置services .AddOrchardCms() .ConfigureServices(tenantServices tenantServices.PostConfigureResourceOptions(options { options.UseCdn true; }));注意这里使用了PostConfigure来覆盖站点设置的值如果模块本身不依赖站点设置则直接使用Configure即可。或者如果你想使用前文提到的IShellConfigurationservices .AddOrchardCms() .ConfigureServices((tenantServices, serviceProvider) { // 这里也可以改从注入的 IConfiguration 实例获取配置值。 // 那同样能访问标准 ASP.NET Core 配置键 // 但无法获得上文所述的全部层级化配置源支持。 var shellConfiguration serviceProvider.GetRequiredServiceIShellConfiguration(); tenantServices.PostConfigureResourceOptions(options { options.UseCdn shellConfiguration.GetValuebool(OrchardCore_Resources:UseCdn); }); });IShellConfiguration在租户服务容器中可直接通过GetRequiredServiceIShellConfiguration()获取这印证了它作为租户级配置抽象被注入到 Shell 作用域服务的定位。注意在管理后台不会显示这次覆盖已经发生界面上显示的仍将是站点设置中配置的值。因此如果选择这种方式你需要自行告知用户实际生效的配置。实时租户选项IOptionsMonitor与信号驱动的变更令牌Orchard Core 保留了标准的IOptionsMonitorTOptions实现。若要让某个 Options 类型在租户数据变化后自动刷新需要为其注册 Orchard Core 的信号驱动IOptionsChangeTokenSourceTOptions注册扩展方法位于 src/OrchardCore/OrchardCore.Abstractions/Options/OptionsServiceCollectionExtensions.csservices.AddSignalOptionsChangeTokenSourceTOptions();何时用IOptionsMonitor何时用IOptions当 Options 类型由可变租户状态构建如站点设置、文档等可以通过后台修改、无需重启应用的数据时使用IOptionsMonitorTOptions以便变更后自动刷新当值在租户 Shell 生命周期内实际上不可变例如只来自启动代码或静态配置时继续使用IOptionsTOptions即可。如何在设置编辑后触发刷新当设置编辑器更新了某个 Options 类型所依赖的数据时通过IOptionsUpdateNotifier请求失效通知接口定义见 src/OrchardCore/OrchardCore.Abstractions/Options/IOptionsUpdateNotifier.cs。Orchard Core 会把通知推迟到当前文档会话document session提交成功之后再分发——因此失败或回滚的更新不会刷新 Options 缓存。其底层实现位于 src/OrchardCore/OrchardCore/Options/DefaultOptionsUpdateNotifier.csRequestUpdateTOptions会把待更新项收集到_pendingUpdates集合通过IDocumentStore.AfterCommitSuccess记录提交成功标志再通过ShellScope.AddDeferredTask注册延迟任务——只有提交成功且存在待更新项时才调用ISignal.SignalTokenAsync(OptionsUpdateSignal.GetKey(...))触发信号。SignalOptionsChangeTokenSourceTOptions源码则通过_signal.GetToken(OptionsUpdateSignal.GetKey(typeof(TOptions), Name))把 Options 的变更令牌挂接到该信号上从而实现提交成功后、缓存的IOptionsMonitor被自动刷新。完整的落地示例public sealed class Startup : StartupBase { public override void ConfigureServices(IServiceCollection services) { services.AddSignalOptionsChangeTokenSourceMyOptions(); } } public sealed class MySettingsDisplayDriver : SiteDisplayDriverMySettings { private readonly IOptionsUpdateNotifier _optionsUpdateNotifier; public MySettingsDisplayDriver(IOptionsUpdateNotifier optionsUpdateNotifier) { _optionsUpdateNotifier optionsUpdateNotifier; } public override async TaskIDisplayResult UpdateAsync(ISite site, MySettings settings, UpdateEditorContext context) { await context.Updater.TryUpdateModelAsync(settings, Prefix); if (context.Updater.ModelState.IsValid) { _optionsUpdateNotifier.RequestUpdateMyOptions(); } return await EditAsync(site, settings, context); } } public sealed class MyService { private readonly IOptionsMonitorMyOptions _options; public MyService(IOptionsMonitorMyOptions options) { _options options; } public string GetValue() _options.CurrentValue.SomeSetting; }使用建议仅在验证通过之后排队更新请求且只为受变更影响的 Options 类型发起请求通知器是单向的Orchard Core 会按 Shell 作用域合并请求并在提交后统一分发因此不存在RemoveUpdateRequest()之类的 API 用于取消先前请求对于命名 Optionsnamed options需要手动为匹配的名字注册IOptionsChangeTokenSourceTOptions即SignalOptionsChangeTokenSourceTOptions并以相同的名字调用RequestUpdateTOptions(name)SignalOptionsChangeTokenSource构造函数接受name参数见 源码在多节点环境中请使用分布式ISignal实现例如OrchardCore.Redis模块提供的 Redis Bus 特性确保每个节点都能使其本地IOptionsMonitorTOptions缓存失效并从已提交的租户状态重建最新 Options。ORCHARD_APP_DATA环境变量App_Data文件夹的位置可以通过设置ORCHARD_APP_DATA环境变量来改变。该常量定义于 src/OrchardCore/OrchardCore.Abstractions/ShellOptionConstants.csOrchardAppData ORCHARD_APP_DATA默认路径App_Data默认租户目录Sites。支持三种路径形式相对于应用路径的相对路径./App_Data绝对路径/path/from/root完整限定路径D:\Path\To\App_Data如果该文件夹不存在应用会尝试自动创建。全局租户配置App_Data/appsettings.json前文讨论的IShellConfiguration设置也可以放在App_Data/appsettings.json文件中该文件默认不会创建。任何在此文件中指定的设置都会覆盖来自启动项目Startup Project的对应设置。租户文件夹中的IShellConfiguration每个租户文件夹下的App_Data/Sites/{tenant_name}/appsettings.json同样承载IShellConfiguration配置。该文件是可变的会在租户 Setup 期间被写入。因此从环境名Environment Name读取配置在该场景下不受支持这些appsettings.json不需要OrchardCore段键直接平铺即可{ OrchardCore_Media: { // 针对该租户的特定配置 } }其读写逻辑在 src/OrchardCore/OrchardCore/Shell/Configuration/ShellConfigurationSources.cs 中可以看到AddSourcesAsync通过AddTenantJsonFile(Path.Combine(_container, tenant, appsettings.json), optional: true)把该文件加入配置构建器_container即App_Data/SitesSaveAsync会先解析现有文件内容再合并写入的键值并序列化回文件RemoveAsync则在删除租户时清理该文件。配套的抽象接口IShellConfigurationSources源码定义了AddSourcesAsync、SaveAsync、RemoveAsync三个操作方便替换为其他存储实现。通过环境变量配置IShellConfiguration环境变量也会被翻译成IShellConfiguration使用双下划线__作为层级分隔符例如OrchardCore__OrchardCore_Media__MaxFileSize OrchardCore__Default__OrchardCore_Media__MaxFileSize OrchardCore__MyTenant__OrchardCore_Media__MaxFileSize以上三个示例分别对应全局模块配置、Default 租户的模块配置、MyTenant 租户的模块配置。注意为支持 Linux下划线_被用作分隔符例如OrchardCore_Media。OrchardCore.Media这种点号写法仅为向后兼容而保留使用者应迁移到下划线_模式。配置源加载顺序默认情况下Orchard Core 站点在启动项目的Program.cs中使用默认 BuilderCreateDefaultBuilder因此IConfiguration的加载顺序为启动 ASP.NET Core 项目例如 OrchardCore.Cms.Web.csproj 的appsettings.json或按环境区分的appsettings.Development.json用户机密User Secrets——仅当环境为Development时环境变量Environment Variables或通过 Azure 以环境变量形式提供的 AppSettings命令行参数Command Line Args之后IShellConfiguration会追加以下来源全局租户配置App_Data/appsettings.json位于App_Data/Sites/{tenant_name}/appsettings.json下的各租户独立配置文件。注意具有相同键、后加载的配置会覆盖先加载的配置后加载者胜出last wins。这一后加载者胜出的规则在ShellConfiguration的构建逻辑中也有体现租户配置由ConfigurationBuilder依次叠加应用配置、App_Data全局配置与租户文件配置后构建见 ShellConfiguration.cs越靠后的来源优先级越高。部署场景下的配置Azure App Settings在 Windows 或 Linux 环境下均作为环境变量提供支持Azure DevOps 或其他 CI/CD 流水线在所有平台上均受支持。可使用 Json Path Transformations 对appsettings.json文件做转换并从流水线变量或密钥存储如 Azure Key Vault提供应用机密预览版nightly dev builds如果使用预览包源preview package feed构建CI/CD 流水线需要提供带有该包源地址的NuGet.Configconfiguration packageSources add keynuget valuehttps://api.nuget.org/v3/index.json/ add keypreview valuehttps://nuget.cloudsmith.io/orchardcore/preview/v3/index.json / /packageSources /configuration备用存放位置Alternate locations存储在App_Data文件夹中的IShellConfiguration值以及各租户的appsettings.json文件也可以存放在其他位置。详细内容请参阅 Shells 章节其中包括把 Shell 与租户配置迁移到 Azure Blob 存储或数据库的方案如OrchardCore_Shells_Azure、OrchardCore_Shells_Database配置段示例见 src/OrchardCore.Cms.Web/appsettings.json。小结Orchard Core 的配置体系可以概括为一条清晰的层次链路启动项目appsettings.json→App_Data/appsettings.json全局租户配置 →App_Data/Sites/{tenant}/appsettings.json租户配置再加上环境变量与命令行参数统一汇聚进IShellConfiguration并按后加载者胜出的规则合并。理解这一链路后你可以在租户创建前/后精确注入其专属配置用一份根级配置让所有租户共享数据库并结合TablePrefixPattern/SchemaPattern自动生成隔离前缀通过PostConfigureTOptions或IShellConfiguration从代码覆盖站点设置借助信号驱动的IOptionsChangeTokenSource与IOptionsUpdateNotifier实现设置变更后自动刷新的实时 Options利用ORCHARD_APP_DATA灵活调整数据目录位置从容应对本地、云上与 CI/CD 多环境部署。赞分享CMS后端Web框架【免费下载链接】OrchardCoreOrchard Core is an open-source modular and multi-tenant application framework built with ASP.NET Core, and a content management system (CMS) built on top of that framework.项目地址https://gitcode.com/gh_mirrors/or/OrchardCore点击查看免费下载相关推荐Orchard Core 深度解析基于 ASP.NET Core 的模块化、多租户应用框架与 CMSOrchard Core 深度解析基于 ASP.NET Core 的模块化、多租户应用框架与 CMS 导读 Orchard Core 是一个开源的、基于 ASCMS后端Web框架虚拟桌宠定制零门槛90分钟让它学会打工、摸头和说你的话虚拟桌宠定制零门槛90分钟让它学会打工、摸头和说你的话 VPet虚拟桌宠模拟器是一款免费开源的桌宠软件一只会呼吸、会饿、会生病的小动物趴在屏幕角落你桌面应用游戏开发OGX 多租户 AI 基础设施实战租户隔离、ABAC 与纵深防御配置全解OGX 多租户 AI 基础设施实战租户隔离、ABAC 与纵深防御配置全解 本篇技术指南围绕 OGXOpen GenAI Stack的内建多租户能力展开讲AI应用API网关后端模型推理服务上一篇终极Android悬浮窗开发指南从零构建功能完整的悬浮按钮应用下一篇CANN PTO ISA 入门指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表