ARTICLE DETAIL

资讯详情

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

Elsa Workflow JSON 类型加固:专用序列化类型注册表与兼容性设计实战

Elsa Workflow JSON 类型加固:专用序列化类型注册表与兼容性设计实战 后端工作流自动化流程编排低代码【免费下载链接】elsa-coreThe Workflow Engine for .NET项目地址https://gitcode.com/gh_mirrors/el/elsa-core点击查看免费下载本指南围绕 Elsa.NET 工作流引擎的 Workflow JSON Type Hardening 特性展开系统讲解如何在不破坏既有持久化工作流的前提下重新引入严格的 JSON 类型解析边界。读者将掌握SerializationTypeRegistry的注册机制、别名Alias与遗留 CLR 名称Legacy Name的双通道兼容策略、SerializationTypeResolver的拒绝规则以及事故处理策略Incident Strategy描述符的别名优先契约并可直接应用到自定义模块的序列化配置中。背景为什么需要类型加固Elsa 将工作流定义、工作流状态、触发器与书签Bookmark负载以 JSON 形式持久化。早期版本在反序列化时依赖 CLR 类型名称来还原多态对象这带来两个问题安全性若 JSON 中出现的类型标识符未受约束可能触发任意 CLR 类型加载形成不可信的信任边界一致性公共 API如事故处理策略描述符返回的typeName与工作流 JSON 反序列化所接受的类型标识符不一致导致描述符下拉框拿到了选项、提交后却无法解析的故障。本特性的目标对应 spec.md 中的 User Story 13可以概括为安全升级不破坏存量升级 Elsa 后包含旧版本 CLR 类型名的既有工作流 JSON 仍可读未知或不安全的类型标识符被明确拒绝API 契约前后一致公开描述符返回的类型标识符与工作流 JSON 接受的标识符一致可原样提交回去信任边界可扩展模块、宿主应用与第三方扩展可以显式注册工作流可序列化类型及其遗留名称而不再借用表达式Expression的类型别名配置充当信任边界。架构决策专用注册表而非表达式别名research.md 记录了三条核心决策及其取舍采用专用工作流 JSON 注册表为TypeJsonConverter、PolymorphicObjectConverter、工作流状态序列化、书签负载序列化、触发器比较、哈希与描述符契约统一使用独立的注册表与选项对象。原因在于 issue 明确拒绝以ExpressionOptions作为工作流 JSON 的信任边界——表达式别名仍然保留给表达式求值与设计器变量元数据使用两者互不干扰。被否决的替代方案包括复用IWellKnownTypeRegistry它由ExpressionOptions驱动以及直接回退到Type.GetType会加载任意 CLR 名称。显式遗留兼容名称兼容期读取同时接受别名与已注册的遗留名称包括简单程序集限定名、完整程序集限定名仅限已注册类型以及基于已注册元素类型的受支持集合包装类型。信任边界始终是注册表而不是程序集探测。被否决的宽泛程序集白名单方案因为难以推理、且可能意外暴露受信任程序集中的无关类型而被放弃。别名优先的公开描述符契约事故处理策略描述符应返回工作流 JSON 别名兼容期内旧的 CLR 名称仍可作为输入被读取。这是对描述符返回 CLR 名而加固后的读取期望别名这一故障的直接回应。数据模型三个核心构件data-model.md 将数据模型归纳为三部分构件职责位置SerializationTypeOptions存储工作流 JSON 别名 → 具体类型映射、可选遗留名称映射并提供工作流负载所需的默认基元与 JSON 岛别名Elsa.Common使非工作流序列化层也能共享同一信任边界SerializationTypeRegistry由SerializationTypeOptions构建的运行时注册表解析别名与已注册遗留名称、列出已注册类型、返回写入新 JSON 与公开描述符时优先使用的别名Elsa.CommonWorkflow Type Identifier别名Alias作为新 JSON 的稳定首选标识符遗留名称Legacy Name作为旧 JSON 或旧客户端的兼容标识符贯穿工作流 JSON 与 API 负载关键设计点是SerializationTypeOptions位于 Elsa.Common 模块这样工作流核心、运行时、API 乃至其他模块可以共享同一个信任边界而不是各自维护一份配置。源码实现从选项到解析器的完整链路SerializationTypeOptions默认别名与注册 APISerializationTypeOptions.cs 的构造函数预置了一批基元与 JSON 相关别名覆盖工作流负载的常见形态数值与基础类型Int16、Int32、Int64含遗留名Long、Single、Double、Decimal、Boolean、String、Object时间与特殊类型Guid、DateTime、DateTimeOffset、TimeSpan、Stream、ByteArrayJSON 岛类型JSONExpandoObject、JsonElement、JsonNode、JsonObject、JsonArray字典类型StringDictionary、ObjectDictionary、StringMap、ObjectMap。注册 API 分为两类RegisterTypeAlias(type, alias)注册首选别名同时写入正向与反向映射RegisterLegacyTypeName(type, typeName)仅注册兼容读取名称RegisterLegacySimpleAssemblyQualifiedName(type)将类型的简单程序集限定名注册为遗留标识符。SerializationTypeOptionsExtensions模块友好的扩展方法SerializationTypeOptionsExtensions.cs 提供了面向泛型类型的便捷入口是模块注册时的主要 APIAddTypeAliasT(alias)/AddTypeAliasT()注册首选别名AddTypeAliasWithLegacyNameT(alias)同时注册首选别名与当前简单程序集限定名作为遗留名这是既写别名、又兼容旧名最常用的组合AddLegacySimpleAssemblyQualifiedNameT()仅为兼容期读取注册简单程序集限定名AddSimpleAssemblyQualifiedTypeAlias(type)将简单程序集限定名本身作为首选别名适用于仅需兼容的旧类型。SerializationTypeRegistry双向字典与空值处理SerializationTypeRegistry.cs 内部维护两个字典_aliasTypeDictionary标识符 → 类型忽略大小写用于读取解析_typeAliasDictionary类型 → 别名用于写入时挑选首选别名。构造时从SerializationTypeOptions的两个只读字典批量灌入。值得注意的一个细节当注册的类型是基元或非空值类型时注册表会自动补一个{alias}?的可空别名映射从而让Int32?这类可空写法也能被解析。对外能力包括TryGetAlias、TryGetType、ListTypes其中ListTypes用于兼容解析时获取已注册类型快照。SerializationTypeResolver安全解析的守门人SerializationTypeResolver.cs 是类型解析的核心其解析顺序为直接命中注册表registry.TryGetType(typeAlias)优先数组类型形如String[]的别名先解析元素别名再MakeArrayType泛型集合形如ListInt32的别名仅限内置白名单集合定义IEnumerable、ICollection、IList、IReadOnlyCollection、IReadOnlyList、ISet、List、HashSet、Collection且元素类型必须能解析注册遗留名称先尝试与已注册类型的简单程序集限定名/完整程序集限定名精确匹配再尝试Type.GetType——但程序集解析被限制在已注册类型的程序集与List所在的 corelib 范围内任何未知 CLR 名称都会解析失败并被拒绝。解析失败时抛出JsonException错误信息明确说明只有已注册别名与受支持的复合别名可以被反序列化。反向的TryGetAlias同样支持数组与泛型集合的别名合成如String[]、ListInt32保证写出去的别名一定能被读回来。此外TryGetInstantiableCollectionType能把集合接口如IListT映射到可实例化具体类型如ListT供多态物化使用。这套实现印证了性能目标普通序列化路径全程基于字典查找没有任何反射扫描同时通过限制程序集解析范围杜绝了任意 CLR 类型加载。注册落地内置别名从何处来WorkflowsFeature.cs 的AddElsaCore方法通过services.ConfigureSerializationTypeOptions集中注册了工作流核心的别名包括状态与异常类型ExceptionState、FaultException、VariablesDictionary、Token、Exception及一系列具体异常类型ArgumentException、TimeoutException等存储驱动WorkflowStorageDriver、WorkflowInstanceStorageDriver、MemoryStorageDriver均采用别名 遗留名双注册事故处理策略FaultStrategy、ContinueWithIncidentsStrategy对应 IncidentStrategies 下的两个实现流程与 JSON 类型FlowJoinMode并显式注册了旧 CLR 名Elsa.Workflows.Core.Activities.Flowchart.Models.FlowJoinMode, Elsa.Workflows.Core、JObject、JArray。同一文件还注册了ISerializationTypeRegistry单例实现SerializationTypeRegistry并将其注入JsonWorkflowStateSerializer、SafeSerializer、BookmarkPayloadSerializer等序列化器。任务清单 tasks.md 的 T003T008 正是对应这套先在Elsa.Common建注册表再切换Elsa.Workflows.Core各转换器的落地顺序。事故处理策略描述符别名优先的双向契约事故处理策略描述符端点的实现位于 Endpoint.cs端点路由为GET /descriptors/incident-strategies需要WorkflowPermissions.DescriptorsIncidentStrategies的View权限构造IncidentStrategyDescriptor时从注入的ISerializationTypeRegistry查询首选别名workflowJsonTypeRegistry.TryGetAlias(type, out var alias) ? alias : type.FullName!——即优先返回别名仅在未注册时回退到完整类型名客户端模型 IncidentStrategyDescriptor.cs 承载TypeName字段。这正符合 contracts/workflow-json-type-identifiers.md 的契约GET /descriptors/incident-strategies返回的typeName来自共享序列化类型注册表客户端应原样持久化/提交返回的typeName兼容期内旧客户端提交的已注册 CLR 遗留名也仍然可读。兼容窗口与拒绝规则结合 contracts/workflow-json-type-identifiers.md 与 workflow-core.md 的文档描述识别符规则可归纳为读取反序列化时接受已注册别名已注册遗留名称包括旧工作流 JSON 中出现的、被显式注册的 CLR 名称受支持的集合包装别名——仅限已知集合定义且封闭于已注册元素类型之上如ListInt32数组别名如String[]。读取时拒绝未知或不可信的 CLR 类型名称不进行动态加载抽象类、接口、开放泛型等不可直接实例化的目标不适当的集合类型目标——除非解析器能将已知集合接口映射到具体集合类型如IListT→ListT。写入序列化时已注册类型优先写出首选别名数组与泛型集合会合成可读回的复合别名。边界情况来自 spec.md 的 Edge Cases类型在程序集间迁移或重命名、JSON 岛中形似类型元数据但实际是普通数据、运行时触发器与书签负载中的多态值、宿主应用在核心服务配置完成后注册自定义类型等均属于该信任模型必须覆盖的场景。模块注册指引第三方如何接入第三方模块与宿主应用注册工作流可序列化类型的方式与内置注册完全一致——在自己的 Feature 的Apply方法里通过services.ConfigureSerializationTypeOptions调用扩展方法即可services.ConfigureSerializationTypeOptions(options { // 首选别名 遗留 CLR 名双通道注册 options.AddTypeAliasWithLegacyNameMyPayload(nameof(MyPayload)); // 仅兼容读取旧 JSON 中的 CLR 名 options.AddLegacySimpleAssemblyQualifiedNameLegacyPayload(); // 仅注册首选别名 options.AddTypeAliasNewPayload(nameof(NewPayload)); });注意两个边界一是仅注册为表达式使用的类型不会被工作流 JSON 解析接受除非同时注册为工作流可序列化类型二是不要用ExpressionOptions充当工作流 JSON 的信任边界。任务清单 tasks.md 的 T019T020 记录了 Elsa.Http、Elsa.Scheduling、Elsa.Resilience、Elsa.Alterations、Elsa.Persistence.EFCore、Elsa.Workflows.Management、Elsa.Workflows.Runtime 等模块把负载注册从表达式选项迁往工作流 JSON 选项的过程是第三方迁移的现成参照。验证与测试quickstart.md 给出了四步验证路径通过工作流 Feature 注册内置工作流 JSON 别名各序列化工作流负载的模块注册各自的负载别名确认TypeJsonConverter与PolymorphicObjectConverter使用共享序列化注册表而非表达式选项运行定向测试dotnet test test/unit/Elsa.Workflows.Core.UnitTests/Elsa.Workflows.Core.UnitTests.csproj --filter SerializationTypeResolverTests dotnet test test/unit/Elsa.Workflows.Runtime.UnitTests/Elsa.Workflows.Runtime.UnitTests.csproj --filter WorkflowRuntimeFeatureTests从任务清单可见测试覆盖了多个层面对应 tasks.md解析器回归SerializationTypeResolverTests覆盖专用注册表兼容性以及仅表达式别名的类型不被工作流 JSON 接受的反向回归T009T010描述符回归Elsa.Workflows.Api.UnitTests/Endpoints/IncidentStrategies/ListTests验证描述符输出别名、遗留名仍可读T013运行时与触发器WorkflowRuntimeFeatureTests、WorkflowTriggerEqualityComparerTests验证运行时负载解析与触发器比较走专用注册表T017T018。这些测试对应 spec.md 的 Success Criteria遗留 JSON 夹具全部可加载、不安全类型全部被拒、事故策略描述符与提交流程双向使用同一契约、加固测试不依赖表达式别名配置。常见问题与故障排查Q1升级后旧的持久化工作流读不出来了先确认旧 JSON 中的类型标识符是否已被注册。兼容期内只有已知 Elsa 工作流相关 CLR 名称 显式注册的宿主/扩展遗留名称可读见 spec.md 的 Assumptions。若为自研类型用AddLegacySimpleAssemblyQualifiedNameT()或AddTypeAliasWithLegacyNameT(alias)注册后再试。Q2自定义类型注册了别名但工作流 JSON 仍拒绝检查该类型是否注册到了SerializationTypeOptions工作流序列化信任边界而非ExpressionOptions同时确认类型不是抽象类、接口、开放泛型或不适当的集合目标。Q3描述符返回的 typeName 提交回去解析失败描述符已优先返回注册表别名Endpoint.cs 的TryGetAlias分支。若仍失败多半是该策略类型未在WorkflowsFeature或对应模块中注册别名检查SerializationTypeOptions配置。Q4JSON 里看起来像类型元数据但其实是普通数据JSON 岛如JSON别名对应的ExpandoObject保留为普通 JSON 数据语义不会参与类型解析只有显式携带类型标识符的多态字段才走注册表解析。延伸阅读需求与验收场景spec.md决策记录research.md数据模型data-model.md标识符契约contracts/workflow-json-type-identifiers.md实现任务清单tasks.md官方文档对应章节workflow-core.md核心实现SerializationTypeOptions.cs、SerializationTypeRegistry.cs、SerializationTypeResolver.cs、WorkflowsFeature.cs赞分享后端工作流自动化流程编排低代码【免费下载链接】elsa-coreThe Workflow Engine for .NET项目地址https://gitcode.com/gh_mirrors/el/elsa-core点击查看免费下载相关推荐DARC 访问指南使用 darc.js 连接并操作已部署的 DARC 虚拟机DARC 访问指南使用 darc.js 连接并操作已部署的 DARC 虚拟机 本文以 DARC 官方文档 Access to a deployed DARC后端工作流自动化流程编排低代码Elsa Workflow JSON 类型加固SerializationTypeRegistry 数据模型与信任边界解析Elsa Workflow JSON 类型加固SerializationTypeRegistry 数据模型与信任边界解析 导读 本文围绕 ElsaThe W后端工作流自动化流程编排低代码CANN/asc-devkit 矩阵计算搬入接口总体说明a nameZH CN_TOPIC_0000002569070899 /a 矩阵计算的搬入是Ascend C编程框架中用于数据搬运的一类核心接人工智能深度学习算子库CANNAscend上一篇三步掌握AI斗地主如何用DouZero智能助手提升你的游戏胜率下一篇Nature Skills 统计报告审查用 nature-statistics 写透 p 值、重复数与图注统计的 5 步指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表