首页 / 资讯中心 / 文章详情

Orchard Core Publish Later 模块实战指南:为内容项设置定时发布

Orchard Core Publish Later 模块实战指南:为内容项设置定时发布 ★ FEATURED ARTICLE
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点击查看免费下载导读Publish Later定时发布是 Orchard Core 中一个轻量的内容管理模块它允许编辑者为草稿状态的内容项指定一个未来的发布时间由后台任务在时间到达时自动完成发布而无需人工干预。本文以官方模块文档为主体结合该模块在仓库中的完整源码实现数据模型、索引、显示驱动、后台任务带你掌握从功能启用、内容类型配置、编辑器操作到编程式调度与边界行为的全部细节并理解 UTC 时区转换与后台轮询机制背后的工作原理。模块概览与启用模块定位OrchardCore.PublishLater模块的作用一句话概括将一个草稿内容项安排schedule在指定日期时间自动发布。它不是立即发布而是把计划时间保存在内容项上等待后台任务触发。从模块清单 Manifest.cs 可以看到它的声明信息模块名Publish Later分类Content Management依赖OrchardCore.Contents描述The Publish Later module adds the ability to schedule content items to be published at a given future date and time.启用与配置步骤在后台的Features功能页面启用Publish Later功能。进入Content内容→ Content Definition内容定义→ Content Types内容类型编辑需要支持定时发布的内容类型。为该类型添加 Publish Later Part 部件并保存定义。该部件是Attachable可附加的可以挂接到任意内容类型上。数据迁移 Migrations.cs 中正是这样定义部件与索引的await _contentDefinitionManager.AlterPartDefinitionAsync(PublishLaterPart, builder builder .Attachable() .WithDescription(Adds the ability to schedule content items to be published at a given future date and time.));部件本身极其简单只存储一个 UTC 时间字段。数据模型 PublishLaterPart.cs 完整代码如下using OrchardCore.ContentManagement; namespace OrchardCore.PublishLater.Models; public class PublishLaterPart : ContentPart { public DateTime? ScheduledPublishUtc { get; set; } }计划时间保存在PublishLaterPart.ScheduledPublishUtc上值为null表示没有活动计划。所有时间统一以UTC存储这是理解本模块时区行为的关键。编辑器中的调度操作如何安排一次发布当一个内容项已附加 Publish Later Part 时编辑该内容项会看到在编辑器操作区Actions 区域出现Publish Later控件一个datetime-local日期时间输入框输入日期时间后点击Publish Later稍后发布按钮。这一步的语义需要特别强调它保存的是最新版本latest version草稿及其计划并不会立即发布内容。如果该内容已存在已发布版本那么在计划草稿被发布之前线上live版本保持不变——即先存草稿、到期再发。前端控件由视图 PublishLaterPart.Edit.cshtml 渲染其核心片段如下input asp-forScheduledPublishLocalDateTime typedatetime-local classform-control content-preview-select / button classbtn btn-outline-success text-nowrap btn-publish-later typesubmit namesubmit.Save valuesubmit.PublishLaterT[Publish Later]/button当已有活动计划时还会额外渲染一个Cancel Publish Later取消稍后发布按钮valuesubmit.CancelPublishLater。修改与取消计划修改计划重新输入一个日期时间并保存草稿即可覆盖原计划。取消计划清空日期并保存或直接点击Cancel Publish Later按钮。后端接收这些操作的是显示驱动 PublishLaterPartDisplayDriver.cs 的UpdateAsync方法逻辑非常直白if (viewModel.ScheduledPublishLocalDateTime null || httpContext.Request.Form[submit.Save] submit.CancelPublishLater) { part.ScheduledPublishUtc null; } else { part.ScheduledPublishUtc await _localClock.ConvertToUtcAsync(viewModel.ScheduledPublishLocalDateTime.Value); }即输入为空或点击取消按钮时清空计划ScheduledPublishUtc null否则把本地时间通过ILocalClock.ConvertToUtcAsync转为 UTC 后保存。内容列表中的计划显示在内容管理列表SummaryAdmin中凡是有活动计划的内容项都会显示其计划发布时间。该摘要形状由Display方法注册在Meta:25位置PublishLaterPartDisplayDriver.csreturn InitializePublishLaterPartViewModel(${nameof(PublishLaterPart)}_SummaryAdmin, model PopulateViewModel(part, model)) .Location(OrchardCoreConstants.DisplayType.SummaryAdmin, Meta:25);对应视图 PublishLaterPart.SummaryAdmin.cshtmlif (Model.ScheduledPublishUtc.HasValue) { div span classhintT[Scheduled to be published on {0}, (object)(await DisplayAsync(await New.DateTime(Utc: Model.ScheduledPublishUtc)))]/span /div }权限控制调度控件只在当前用户对内容项拥有标准PublishContent权限时才可见、可操作。Orchard Core 会自动应用所有者相关owner-specific和内容类型相关content-type-specific的权限变体。本模块不定义独立的调度权限。权限检查发生在两处互为印证服务端PublishLaterPartDisplayDriver.cs 的UpdateAsync中先调用IAuthorizationService.AuthorizeAsync(httpContext?.User, CommonPermissions.PublishContent, part.ContentItem)通过才处理提交值不通过则原样保留ScheduledPublishUtc。前端PublishLaterPart.Edit.cshtml 中AuthorizeAsync(User, CommonPermissions.PublishContent, Model.ContentItem)通过后才渲染输入框和按钮。日期、时间与时区处理双向转换流程写入编辑器接受一个本地日期时间datetime-local输入后台通过ILocalClock.ConvertToUtcAsync转为 UTC 存入ScheduledPublishUtc。读取编辑器展示既有计划时通过ILocalClock.ConvertToLocalAsync把存储的 UTC 值转回当前请求的本地时区。见PopulateViewModelviewModel.ScheduledPublishUtc part.ScheduledPublishUtc; viewModel.ScheduledPublishLocalDateTime part.ScheduledPublishUtc.HasValue ? (await _localClock.ConvertToLocalAsync(part.ScheduledPublishUtc.Value)).DateTime : null;时区来源优先级本地时区由ILocalClock提供其选取顺序为用户时区当User Time Zone功能启用时配置的用户时区优先站点时区否则使用站点site时区服务器系统时区两者都未配置时回退到服务器系统时区。⚠️警告夏令时DST转换是严格的。如果输入的本地时间恰逢夏令时切换中被跳过或重复的时间段转换会失败导致计划无法保存。因此请选择无歧义的本地时间。允许过去的时间编辑器不要求输入值必须晚于当前时间。一个已经过去的时刻会在后台任务下一次运行时立即符合发布条件——换句话说定时发布本质上是一个到达或已过时间就发布的机制。后台发布机制定时任务与轮询频率Scheduled Content Items Publisher计划内容项发布器后台任务默认启用cron 计划为* * * * *即每分钟检查一次到期内容。任务声明见 ScheduledPublishingBackgroundTask.cs[BackgroundTask( Title Scheduled Content Items Publisher, Schedule * * * * *, Description Publishes content items when their scheduled publish date time arrives.)] public sealed class ScheduledPublishingBackgroundTask : IBackgroundTask任务通过 Startup.cs 注册为单例后台任务services.AddSingletonIBackgroundTask, ScheduledPublishingBackgroundTask();每次运行的执行流程每次运行执行四步见DoWorkAsync实现查询符合条件的内容查询PublishLaterPartIndex索引条件是Latest !Published ScheduledPublishDateTimeUtc UtcNow即最新版本、未发布、计划时间早于当前 UTC 时间选出到期项由索引查询天然过滤出所有已到期项清除计划将part.ScheduledPublishUtc null并调用part.Apply()发布内容通过IContentManager.PublishAsync(contentItem)逐个发布。核心代码var itemsToPublish await serviceProvider .GetRequiredServiceISession() .QueryIndexPublishLaterPartIndex(index index.Latest !index.Published index.ScheduledPublishDateTimeUtc _clock.UtcNow) .ListAsync(cancellationToken); ... foreach (var item in itemsToPublish) { var contentItem await contentManager.GetAsync(item.ContentItemId, VersionOptions.Latest); if (contentItem.TryGetPublishLaterPart(out var part)) { part.ScheduledPublishUtc null; part.Apply(); } await contentManager.PublishAsync(contentItem); }注意查询使用的是IClock.UtcNow当前 UTC 时间而非本地时间这正是文档强调任务与当前 UTC 时间比较的原因。时序特性发布只会晚于、不会早于请求的时间发生实际延迟取决于任务调度周期默认最长约 1 分钟、宿主机可用性与处理耗时。因为任务走的是标准内容发布 APIIContentManager.PublishAsync内容处理器content handlers、工作流workflows、索引、通知及其他发布集成都会像编辑器手动发布一样正常执行——例如工作流中挂在内容已发布事件上的逻辑依然会被触发。任务管理与失败语义启用 Background Tasks 功能后可以在后台管理中查看/管理该任务。禁用任务、停止应用或租户tenant不可用都会让到期项保持为草稿等待后续某次运行再处理。任务对到期项无排序、无批次限制地依次处理。若发布某个内容项抛出异常后台任务基础设施会记录错误日志并停止本次运行后续项不再处理下一次运行会重新查询符合条件的项再继续。编程式调度面向自定义模块通过标准内容 API 设置计划本模块不暴露独立的 HTTP API。自定义模块可以完全通过常规内容 API 来调度草稿把PublishLaterPart.ScheduledPublishUtc设为 UTC 值并保存草稿即可。官方文档给出的示例draft.AlterPublishLaterPart(part part.ScheduledPublishUtc scheduledUtc); await contentManager.SaveDraftAsync(draft);前提条件内容类型必须包含PublishLaterPartdraft必须是最新的未发布版本latest unpublished versionscheduledUtc必须表示UTC时间将属性设为null即取消计划。本地时间转换与授权如果代码拿到的是本地时间值可先调用ILocalClock.ConvertToUtcAsync再赋给属性自定义端点必须自行完成授权PublishContent权限检查属于内置显示驱动PublishLaterPartDisplayDriver并不属于PublishLaterPart本身。形状Shapes与定制内置显示驱动暴露两个形状形状位置用途PublishLaterPart_EditActions区域Actions:10编辑器中的调度控件PublishLaterPart_SummaryAdmin后台摘要Meta区域Meta:25内容列表中显示计划时间可以通过**放置placement规则或形状覆盖shape override**自定义它们的渲染。需要说明的是Edit方法返回的是GetEditorShapeType(context)得到的形状名默认为PublishLaterPart_Edit而Display方法固定返回PublishLaterPart_SummaryAdmin。边界行为与底层索引原理索引哪些内容会被纳入待发布集合索引模型 PublishLaterPartIndex.cs 记录了四个字段ContentItemId、ScheduledPublishDateTimeUtc、Published、Latest。索引提供者 PublishLaterPartIndexProvider.cs 的映射逻辑揭示了几个关键边界context.ForPublishLaterPartIndex() .When(contentItem contentItem.HasPublishLaterPart() || _partRemoved.Contains(contentItem.ContentItemId)) .Map(contentItem { // Remove index records of items that are already published or not the latest version. if (contentItem.Published || !contentItem.Latest) { return null; } if (!contentItem.TryGetPublishLaterPart(out var part) || !part.ScheduledPublishUtc.HasValue) { return null; } ... });结合文档的 Edge behavior 小节可以归纳出以下边界规则只有最新的未发布版本会被索引为待发布如果在计划时间到达前手动发布该版本它会从待发布集合中移除因为Publishedtrue不再符合!Published条件且映射返回null会删除对应索引记录。从内容类型中移除PublishLaterPart索引提供者在CreatedAsync/UpdatedAsync时校验内容定义是否仍包含该部件若已移除则执行contentItem.RemovePublishLaterPart()并记录到_partRemoved确保内容项下次创建或更新后不会残留过期部件数据与索引记录防止 stale data 被继续索引。时区变更只影响显示不影响存储时刻任务比较的是当前 UTC 时间之后修改用户或站点的时区只会改变存储时刻在界面上的显示不会改变该时刻本身。发布仍可被内容处理器取消任务使用的是返回布尔值的PublishAsyncAPITaskbool版本但任务本身没有为处理器取消发布的情况增加额外处理逻辑——即如果某个内容处理器拒绝发布任务不会针对该情况做补偿操作。数据库结构数据迁移 Migrations.cs 创建了PublishLaterPartIndex映射索引表包含ContentItemId、ScheduledPublishDateTimeUtc、Published、Latest四列并建立了组合索引IDX_PublishLaterPartIndex_DocumentId覆盖Id、DocumentId、ContentItemId、ScheduledPublishDateTimeUtc、Published、Latest为每分钟的到期查询提供支撑。从UpdateFrom1Async/UpdateFrom2Async的迁移代码还可以看到历史演进早期版本只有ScheduledPublishDateTimeUtc列后续版本才补充了ContentItemId、Published、Latest并重建索引且刻意保留旧列/索引以兼容不同数据库提供者某些数据库不支持直接删索引或改列。模块注册一览Startup.cs 完整展示了模块的服务注册结构AddContentPartPublishLaterPart()UseDisplayDriverPublishLaterPartDisplayDriver()注册部件与显示驱动AddDataMigrationMigrations()注册数据迁移PublishLaterPartIndexProvider同时注册为IScopedIndexProvider与IContentHandler同一实例前者负责维护索引表后者负责在内容创建/更新时做部件残留清理ScheduledPublishingBackgroundTask注册为IBackgroundTask单例。小结Publish Later 模块是 Orchard Core内容即草稿 后台任务轮询架构的典型示例一个仅含单个 UTC 时间字段的 ContentPart配合显示驱动完成本地/UTC 双向转换借助 YesSql 索引实现高效到期查询再通过标准PublishAsyncAPI 保证与手动发布完全一致的处理链路。无论你是通过后台界面使用还是在自定义模块中编程调度掌握ScheduledPublishUtc的 UTC 语义、PublishContent权限约束以及后台任务的每分钟轮询特性就能准确预测和控制内容的上线时机。相关仓库资源官方模块文档src/docs/reference/modules/PublishLater/README.md数据模型PublishLaterPart.cs显示驱动PublishLaterPartDisplayDriver.cs后台任务ScheduledPublishingBackgroundTask.cs索引PublishLaterPartIndex.cs 与 PublishLaterPartIndexProvider.cs迁移Migrations.cs编辑器视图PublishLaterPart.Edit.cshtml赞分享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 的 Archive Later 模块定时自动归档取消发布已发布内容项的完整指南Orchard Core 的 Archive Later 模块定时自动归档取消发布已发布内容项的完整指南 OrchardCore.ArchiveLaterCMS后端Web框架Orchard Core 模块参考指南内置模块全览与 CMS/Core 分类导航Orchard Core 模块参考指南内置模块全览与 CMS/Core 分类导航 导读 本文以 Modules Reference https://link.CMS后端Web框架CANN/asc-devkit SIMT类型转换函数\_\_uint2float\_rz 产品支持情况 | 产品 | 是否支持 | | | | | Ascend 950PR/Ascend 950DT | √ |CMS后端Web框架上一篇ALBERT XLarge v2与其他ALBERT版本对比v2版本的10大改进点下一篇Vue Router 2 命名路由Named Routes完全指南配置、跳转与源码级原理创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?
咨询建站