- CMS
- 后端
- Web框架
【免费下载链接】OrchardCore
Orchard 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.
Orchard Core 1.8.1 是 2024 年 1 月 9 日发布的一个补丁版本,聚焦于四项关键修复与能力增强:GraphQL 依赖项修复、内容类型默认显示名的自动补全、ShellScopeServices对 Keyed Services 的完整支持,以及 Media Field 依赖修复。本文基于 src/docs/releases/1.8.1.md 的官方发布说明,结合当前仓库源码逐条还原这些变更的底层实现与影响范围,帮助开发者在升级 1.8.1 时准确评估变更点,并理解多租户 DI 容器与内容定义元数据的工作机制。
版本概览与升级背景
| 项目 | 内容 |
|---|---|
| 版本号 | 1.8.1 |
| 发布日期 | 2024 年 1 月 9 日 |
| 上一版本 | 1.8.0 |
| 变更性质 | 缺陷修复 + 能力增强,均为向后兼容的增量改动 |
该版本没有引入破坏性的 API 变更,四条改动分别落在 GraphQL 模块、内容管理抽象层(Content Management Abstractions)和多租户 Shell 作用域(Shell Scope)三个区域。下面按发布说明的顺序逐条展开。
一、修复 GraphQL 依赖项(PR #15015)
发布说明第一条为 "Fix dependencies for GraphQL",由 MikeAlhayek 提交。该修复针对的是OrchardCore.ContentManagement.GraphQL项目与其依赖模块之间的包引用关系问题。
从当前仓库的注册入口 ServiceCollectionExtensions.cs 可以看到,AddContentGraphQL()扩展方法集中注册了 GraphQL 所需的 Schema 构建器、查询类型、权限提供者与过滤类型:
public static IServiceCollection AddContentGraphQL(this IServiceCollection services) { services.AddSingleton<ISchemaBuilder, ContentItemQuery>(); services.AddSingleton<ISchemaBuilder, ContentTypeQuery>(); services.AddTransient<ContentItemInterface>(); services.AddTransient<ContentItemType>(); services.AddPermissionProvider<Permissions>(); services.AddScoped<IContentTypeBuilder, TypedContentTypeBuilder>(); services.AddScoped<IContentTypeBuilder, DynamicContentTypeQueryBuilder>(); services.AddOptions<GraphQLContentOptions>(); services.AddGraphQLFilterType<ContentItem, ContentItemFilters>(); services.AddWhereInputIndexPropertyProvider<ContentItemIndex>(); return services; }同文件中还提供了AddContentFieldsInputGraphQL(),用于将动态内容字段的索引别名提供者(DynamicContentFieldsIndexAliasProvider)以作用域方式注册,并同时暴露为IIndexAliasProvider与IContentDefinitionEventHandler(源码位置)。
此次依赖修复的实质是补齐这些 GraphQL 注册所依赖的程序集引用(尤其是OrchardCore.Apis.GraphQL.Abstractions、OrchardCore.ContentManagement.Abstractions等),确保在引用OrchardCore.ContentManagement.GraphQL时不会出现编译期缺少依赖或运行时程序集加载失败的问题。对于模块开发者的直接影响是:升级到 1.8.1 后,引用 GraphQL 相关包时的依赖解析更干净,无需手动补充多余的包引用。
二、仅在未指定时设置默认显示名(PR #15013)
第二条 "Set a default display name only when none is specified" 由 giannik 与 MikeAlhayek 共同提交,是本次版本中对内容类型(Content Type)与内容部件(Content Part)元数据行为的修正。
该修复的核心逻辑位于 ContentPartDefinitionBuilder.cs 与同文件第 198-201 行:
if (string.IsNullOrEmpty(settings.DisplayName)) { settings.DisplayName = fieldName; }也就是说,只有当DisplayName设置为空时,系统才会回退使用字段名(或部件名)作为默认显示名;如果开发者已经显式指定了显示名,则该值会被原样保留,不会被覆盖。
在类型层面,ContentTypeDefinition.cs 提供了配套的回退语义:
/// Returns the <see cref="DisplayName"/> value of the type if defined, /// otherwise the technical name of the type. public string GetDisplayName() => string.IsNullOrEmpty(DisplayName) ? Name : DisplayName;配合 ContentTypePartExtensions.cs 中的DisplayName()扩展方法,可以看到完整的显示名解析链:部件级设置中的DisplayName优先,其次回退到内容类型自身的显示名,最后才是部件/字段的技术名称。
这次修复针对的正是此前版本中的一个边界缺陷:在定义新部件或通过 API 修改部件设置时,如果代码路径中存在隐式的默认值写入,可能把用户已配置的显示名覆盖掉。修复后,默认显示名仅在"完全未指定"时补全,语义更符合直觉,也保证了导入导出(Deployment)场景下显示名设置的往返一致性。
三、ShellScopeServices 增加 Keyed Services 支持(PR #14998)
第三条 "Add Keyed services support in ShellScopeServices" 是本次版本中技术含量最高的一项改动,它让 Orchard Core 的多租户 Shell 作用域服务解析与 .NET 8 引入的 Keyed Services 机制完成了对齐。
背景:什么是 Keyed Services
.NET 8 的 Microsoft.Extensions.DependencyInjection 引入了键控服务(Keyed Services),允许同一个服务类型注册多个实现,并通过字符串或对象键来区分。典型用法:
services.AddKeyedSingleton<ICache, MemoryCache>("memory"); services.AddKeyedSingleton<ICache, RedisCache>("redis"); // 按键解析 var cache = serviceProvider.GetRequiredKeyedService<ICache>("redis");在 Orchard Core 中,每个租户(Tenant)拥有独立的 Shell 作用域与组合根(Composition Root),服务解析需要经过ShellScope才能拿到当前租户的容器。此前ShellScopeServices仅实现了普通的IServiceProvider,无法处理键控服务的解析请求。
实现细节
修复后的 ShellScopeServices.cs 实现了IKeyedServiceProvider接口:
public class ShellScopeServices(IServiceProvider services) : IKeyedServiceProvider { private readonly IServiceProvider _services = services; private IServiceProvider Services => ShellScope.Services ?? _services; public object GetKeyedService(Type serviceType, object serviceKey) => Services.GetKeyedService(serviceType, serviceKey); public object GetRequiredKeyedService(Type serviceType, object serviceKey) => Services.GetRequiredKeyedService(serviceType, serviceKey); public object GetService(Type serviceType) => Services?.GetService(serviceType); }ShellScopeServices是一个"感知当前 ShellScope 的 IServiceProvider":当存在活动的ShellScope时优先从其容器解析,否则回退到构造时注入的宿主级IServiceProvider。新增的两个键控解析方法将请求透传给底层的IKeyedServiceProvider,从而让租户容器内也能正常解析键控服务。
配套的容器克隆逻辑
为了让键控 Singleton 在多租户容器中正确共享,ServiceProviderExtensions.cs 中的CreateChildContainer也同步做了配套处理,其中关键的几处分支:
- 按
(ServiceType, ServiceKey)分组遍历服务描述符(第 19 行),确保键控与非键控服务各自独立处理; - 对可释放(
IDisposable)或带工厂的键控单例,通过serviceProvider.GetRequiredKeyedService(ServiceType, ServiceKey)立即从宿主容器解析实例再克隆到租户容器(第 50-55 行); - 对不可释放的键控单例,注册一个带键的工厂
(sp, key) => serviceProvider.GetRequiredKeyedService(service.ServiceType, key),实现"首次请求时才解析"的惰性语义(第 65-69 行); - 当同一类型存在多个键控注册时,使用
GetKeyedServices(ServiceType, ServiceKey)从宿主容器批量解析并仅克隆其中的单例(第 81-83 行)。
此外,OrchardCore.Abstractions 层的 ServiceProviderExtensions.cs 还提供了GetKeyedService扩展方法作为 .NET 10 之前目标框架下的兼容垫片:当底层 provider 实现IKeyedServiceProvider时直接透传,否则抛出InvalidOperationException,明确提示"当前服务提供者不支持键控服务"。
开发者如何使用
升级到 1.8.1 后,模块内可以安全地使用AddKeyedSingleton/AddKeyedScoped注册键控服务,并在构造函数中通过[FromKeyedServices("key")]参数注入或调用GetRequiredKeyedService<T>(key)解析。无论是宿主级还是租户级容器,ShellScopeServices都能正确路由键控解析请求。
四、修复 Media Field 依赖(PR #15017)
第四条 "Fix Media Field dependency" 同样由 MikeAlhayek 提交,修复的是OrchardCore.Media模块中媒体字段(Media Field)相关依赖的注册或引用关系问题。
媒体字段的编辑界面在仓库中对应多套形状(Shape)模板,分别面向不同的使用场景:
- MediaField.Edit.cshtml:标准编辑模板
- MediaField-Attached.Edit.cshtml:附件模式
- MediaField-Gallery.Edit.cshtml:画廊模式
- MediaFieldSettings.Edit.cshtml:字段设置面板
从发布说明的措辞与版本节奏判断,此次修复与上述依赖引用的完整性相关,目的是保证引用媒体字段的项目不会因缺少依赖而出现编辑界面加载失败或字段驱动(Display Driver)注册异常。对于使用MediaField的站点,建议升级后回归验证媒体字段的创建、编辑与保存流程,以及媒体库(Media Library)选择器的打开行为。
升级建议与回归验证清单
综合本次版本的四处变更,建议在升级到 1.8.1 后重点回归以下场景:
- GraphQL 查询:启用 Content Management GraphQL 的站点,验证内容类型与内容项的查询、过滤(Filter)与排序(Sort)行为正常;
- 内容类型显示名:对显式设置了显示名的内容类型、部件与字段做一次导入导出(Deployment)往返验证,确认显示名未被覆盖或丢失;
- 键控服务:若模块中使用了
AddKeyedSingleton/GetRequiredKeyedService,确认在多租户环境下解析正常,单例不会被重复实例化; - 媒体字段:验证媒体字段的编辑、预览与保存,尤其是依赖媒体库选择器的场景。
参考源码路径速查
本次变更涉及的核心文件均可在此仓库中直接查阅:
| 变更点 | 关键文件 |
|---|---|
| GraphQL 依赖修复 | src/OrchardCore/OrchardCore.ContentManagement.GraphQL/ServiceCollectionExtensions.cs |
| 默认显示名 | ContentPartDefinitionBuilder.cs、ContentTypeDefinition.cs |
| Keyed Services 支持 | ShellScopeServices.cs、ServiceProviderExtensions.cs |
| Media Field 依赖修复 | src/OrchardCore.Modules/OrchardCore.Media/Views/MediaField.Edit.cshtml |
需要说明的是,1.8.1 的官方变更日志仅给出了 PR 标题与作者信息,未附详细代码 diff;上文对实现细节的还原基于当前仓库源码与代码结构推断,实际改动以官方提交历史为准。若需了解更早版本的演进脉络,可对照仓库中 src/docs/releases 目录下的其他发布说明。
- CMS
- 后端
- Web框架
【免费下载链接】OrchardCore
Orchard 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.
相关推荐
Zcash 6.3.0-rc1 版本要点解析:Orchard 透明余额 API 修复与 v5 交易版本默认化
Zcash 6.3.0 rc1 版本要点解析:Orchard 透明余额 API 修复与 v5 交易版本默认化 概览 这是 Zcash 6.3.0 rc1 的版本
区块链密码学Bit v1.11.3 版本解析:env.jsonc 的 npm alias 支持、`bit delete --snap` 与依赖处理修复
Bit v1.11.3 版本解析:env.jsonc 的 npm alias 支持、 bit delete snap 与依赖处理修复 本文基于仓库内 relea
开发工具CLI构建工具MCP 服务pnpm 修复详解:Git 依赖在 package.json 中保留 branch、tag 与版本范围,避免 pnpm update 跳回默认分支
pnpm 修复详解:Git 依赖在 package.json 中保留 branch、tag 与版本范围,避免 pnpm update 跳回默认分支 导读 本篇文
包管理器开发工具CLI
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考