ARTICLE DETAIL

资讯详情

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

Elsa 输出转换器发现机制:服务端拥有的 Converter 描述符注册表与 Discovery API

Elsa 输出转换器发现机制:服务端拥有的 Converter 描述符注册表与 Discovery API 后端工作流自动化流程编排低代码【免费下载链接】elsa-coreThe Workflow Engine for .NET项目地址https://gitcode.com/gh_mirrors/el/elsa-core点击查看免费下载Elsa Workflow Engineelsa-core的输出转换器Output Converter体系采用“服务端拥有发现能力”的架构Core 模块拥有 Converter Descriptor 注册表并通过 API 向 Studio 等客户端暴露可过滤的描述符目录客户端不再硬编码转换器实现。本文以 ADR 0013 为核心结合 输出转换器指南、ADR 0011、ADR 0012 与源码实现完整讲解描述符模型、注册表机制、Discovery API、持久化契约与客户端消费方式。读完本文你将掌握如何在 Elsa 中注册可被发现的转换器、如何通过 API 查询兼容转换器以及为什么 Workflow JSON 只持久化id settings而非 CLR 类型。一、设计动机为什么“发现”必须由服务端拥有在传统做法中Studio 或其他客户端为了在下拉列表里展示可用的类型转换能力往往需要硬编码一份转换器清单实现类、显示名、适用类型。这会带来三个问题实现泄露客户端目录里直接出现服务端的 CLR 实现类型客户端与服务端实现细节强耦合漂移风险服务端新增或删除转换器后客户端目录无法自动同步语义归属错乱由 Core 提供一份宽泛的“强制转换”目录会让转换器的业务语义归属变得模糊。ADR 0013 给出的裁决是Core 拥有 Converter Descriptor 注册表Elsa 的 API 暴露按声明的 Source 类型与 Destination 类型过滤的描述符。Studio 和其他客户端消费这份目录而不是自行硬编码转换器实现。同时Core 只提供基础设施和一个参考转换器出现在测试或示例中生产模块自行注册语义归属于自己的转换器Core 不充当通用强制转换目录。这保证了“谁拥有转换语义谁就注册并维护描述符”的责任边界。二、核心模型Converter Descriptor转换器描述符描述符是“可发现但不泄露实现”的载体。OutputConverterDescriptor 是一个 sealed record包含以下字段字段类型说明Idstring稳定、序数ordinal、大小写敏感的转换器 ID是持久化的公开契约SourceTypeType转换器接受的原生输出类型ResultTypeType转换器产生的目标类型DisplayNamestring通过 Discovery 暴露的显示名可本地化Descriptionstring?可选描述同样通过 Discovery 暴露SettingsSchemaJsonElement?可选的、不可变的 JSON Schema描述每个绑定per-binding的设置结构关键点在于描述符只描述不实现。它不含实现实例、不含服务生命周期、不含任何 CLR 实现类型细节——从源码注释可见其定位是“Describes an output converter without exposing its implementation”。注册时描述符与它的依赖注入注册被封装为一个 OutputConverterRegistration 记录public sealed record OutputConverterRegistration( OutputConverterDescriptor Descriptor, string ServiceKey, ServiceLifetime ServiceLifetime);其中ServiceKey必须与描述符的Id完全一致序数比较因为 Elsa 使用 .NET 键控服务keyed service按 Converter ID 解析实现。三、注册表机制大小写敏感的稳定索引OutputConverterRegistry 是 Core 拥有的注册表实现它实现了IOutputConverterRegistry接口核心行为如下内存索引构造时把所有OutputConverterRegistration转换成一个IReadOnlyDictionarystring, OutputConverterRegistration键比较器为StringComparer.Ordinal——即查找是大小写敏感的注册校验构造时立即执行ValidateRegistrations发现以下情况直接抛出InvalidOperationException注册项的ServiceKey与描述符Id不一致同一 ID 被重复注册或存在仅大小写不同的 ID按StringComparer.OrdinalIgnoreCase分组检测描述符的SourceType或ResultType包含泛型参数open-generic因为“开放泛型匹配被推迟”ADR 0012见ValidateDescriptor兼容性查询FindCompatible(sourceType, destinationType)遍历全部描述符用SourceType.IsAssignableFrom(sourceType)判断源兼容用IsAssignableToDestination判断结果类型是否可赋值到目标含对可空目标类型NullableT的底层类型判断。注册入口是 AddOutputConverterTConverter 扩展方法services.AddOutputConverterNumberToTextConverter( new OutputConverterDescriptor( sample.number-to-text.v1, typeof(decimal), typeof(string), Number to text, Formats a decimal using an explicit invariant format., schemaDocument.RootElement));该扩展方法在注册时即调用ValidateDescriptor并做ValidateUniqueId同样拒绝仅大小写不同的重复 ID随后将OutputConverterRegistration以单例方式加入服务集合以descriptor.Id作为 ServiceKey 注册键控服务IOutputConverter→TConverter默认生命周期为Scoped也可通过参数覆盖用TryAddSingletonIOutputConverterRegistry, OutputConverterRegistry()装配注册表。从实现可以看出注册表缓存的是描述符与注册信息而不是转换器实例转换器实例按需从活动工作流执行作用域workflow execution scope中解析输出转换器指南。四、持久化契约Workflow JSON 只保留id settingsADR 0013 的一个核心约束是Workflow JSON 只持久化一个可选的converter对象包含id和 JSONsettings它绝不持久化 CLR 类型、描述符、实例或显示元数据。对应地绑定侧的配置模型是 OutputConverterConfigurationpublic sealed record OutputConverterConfiguration { public string Id { get; } // 稳定 Converter ID public JsonElement? Settings { get; } // 可选的不可变 JSON 设置 }配置一个OutputT绑定activity.Result new Outputdecimal(targetVariable) { Converter new OutputConverterConfiguration( sample.number-to-text.v1, JsonDocument.Parse({format:0.00}).RootElement) };序列化后的绑定 JSON 只增加一个可选对象{ typeName: Decimal, memoryReference: { id: formatted-total }, converter: { id: sample.number-to-text.v1, settings: { format: 0.00 } } }没有配置转换器的绑定则省略converter字段走原有的直接赋值路径输出转换器指南。这种“最小持久化”契约带来两个直接收益前后兼容老版本服务端无法识别converter时配置依然可见、不会被删除见下文 Studio 行为隐私安全显示元数据、实现细节不会泄漏进持久化的定义数据也便于迁移和审计。五、Discovery APIGET /descriptors/output-converters描述符目录通过 Elsa 的 FastEndpoints 端点暴露实现在 Endpoint.csGET /descriptors/output-converters?sourceTypeDecimaldestinationTypeString端点行为要点鉴权要求read:*或read:output-converters权限RequirePermission(WorkflowPermissions.DescriptorsOutputConverters, CoreVerbs.View)单元测试 OutputConverterEndpointTests.cs 明确断言了路由与权限资源的绑定参数sourceType与destinationType均为必填查询参数类型名通过SerializationTypeResolver解析为注册的类型别名如Decimal、String或可安全解析的类型名无法解析时返回 400 并附带错误信息过滤内部调用registry.FindCompatible(sourceType, destinationType)返回兼容的 ID、声明的类型名优先别名、显示元数据以及可选的设置 JSON Schema信息边界返回的OutputConverterDescriptorModel只包含Id、SourceTypeName、ResultTypeName、DisplayName、Description、SettingsSchema。测试断言响应模型不包含SourceType、ResultType、ServiceKey、ServiceLifetime等实现细节属性——它永远不会暴露转换器实例、实现类型或服务生命周期输出转换器指南。对应的 API Client 模型位于 OutputConverterDescriptor 与 ListOutputConvertersResponse供 Studio 等客户端强类型消费。六、Studio 与其他客户端的消费方式“服务端拥有发现”的直接受益者是 StudioStudio 通过 Discovery API 按源/目标类型过滤拿到兼容转换器清单动态渲染选择器而不是内置一张转换器表对于设置Studio 提供schema-driven 表单当描述符携带的是简单对象 Schema 时渲染结构化字段否则提供原始 JSON 对象编辑器面对未知的持久化 Converter ID例如服务端已移除该转换器或来自更新的版本Studio 仍保持该配置可见不擅自删除面对不支持 Discovery 的老服务端Studio 也不会因为查询失败而删除已有配置。这种“服务端目录 客户端渲染 对未知/旧版宽容”的组合正是 ADR 0013 想要达成的解耦目标转换器的增删与展示元数据完全由服务端驱动客户端实现与版本可以独立演进。七、参考转换器与生产注册的边界ADR 0013 明确Core 只提供基础设施与参考转换器位于测试或示例中生产模块注册语义归属于自己的转换器而不是由 Core 提供一份宽泛的强制转换coercion目录。测试中的参考实现 ReferenceOutputConverter.cs 展示了最小实现模式实现IOutputConverter.Convert从context.Settings读取可选 JSON 设置如prefix拼接后返回结果。IOutputConverter 接口本身也体现这一边界——它只要求两个成员public interface IOutputConverter { // 将非空原生输出值转换为绑定值 object? Convert(OutputConversionContext context); // 校验可选的每绑定设置返回的错误消息不得包含敏感设置值 IEnumerablestring ValidateSettings(JsonElement? settings) []; }转换器必须是同步、确定、无副作用的其上下文只包含原生值、声明的源/目标类型和不可变的 JSON 设置依赖通过构造函数注入实例从活动工作流作用域解析而缓存中的描述符绝不保留作用域服务ADR 0012。输出转换器指南 中给出了完整的可运行示例NumberToTextConverter及其注册、绑定配置与序列化 JSON与本文描述的注册表、Discovery API 共同构成端到端闭环。八、验证与失败行为从定义校验到运行时故障虽然 ADR 0013 聚焦“发现”但发现出的描述符最终要服务于绑定执行其验证链路如下输出转换器指南定义校验在定义被接受/物化时Elsa 检查绑定是否有可解析的变量或工作流输出目标、Converter ID 是否已注册、声明的输出类型与转换器源类型是否兼容、转换器结果类型是否可赋值到目标并执行 JSON Schema 与转换器自有设置校验对应处理器见 ValidateOutputConverters.cs运行时重复安全校验解析、兼容、校验、调用等步骤在运行时再次检查失败语义转换是同步的发生在 Elsa 写入目标之前因此失败时目标保持原值不变ADR 0011null 原生值不经过转换器调用只送达允许 null 的目标故障管道运行时失败以OutputConversionException进入活动正常故障管道持久化的异常状态只包含安全的结构化身份与失败阶段排除原生值、原始设置与转换器异常详情——与描述符“不暴露实现”的设计一脉相承是隐私安全设计的一部分对应测试见 OutputConversionExceptionStateTests.cs。九、操作指南与最佳实践结合 输出转换器指南 与 ADR 0012/0013使用这套“服务端发现”体系时应注意ID 即契约Converter ID 是持久化的公开契约。查找保持大小写敏感不要为破坏性行为或设置变更复用同一 ID应注册新的带版本号 ID如sample.number-to-text.v2环境因素显式化locale、时区、舍入等环境相关选择应做成显式设置项而不是依赖转换器内部的隐式环境保持无副作用不要在转换器内执行 I/O 或修改工作流状态异步或带副作用的需求应使用活动输入或专门的 Activity删除即漂移将转换器移除视为部署漂移——之前发布且引用它的工作流会在赋值时故障升级/降级服务端版本时要确保注册表与持久化 ID 一致语义归属谁拥有转换语义谁就在自己的模块中注册描述符不要让 Core 承担通用强制转换目录的职责。十、设计决策脉络本文所述机制是三个 ADR 的协同结果ADR 0011Output conversion at binding is synchronous——转换发生在绑定赋值点且为同步操作这是描述符与绑定 JSON 可以保持最小化只需id settings的前提ADR 0012Output converters use explicit stable identities——明确序数大小写敏感的稳定 ID、拒绝重复/仅大小写不同的注册、拒绝开放泛型、转换器必须同步确定无副作用这定义了描述符Id字段的契约强度ADR 0013Output converter discovery is server-owned——即本文主题注册表归 Core 所有、API 暴露可过滤描述符、客户端消费目录而非硬编码实现、Workflow JSON 只持久化id settings、生产模块注册自己的转换器。三者共同保证了转换器的实现、展示与语义完全由服务端模块自治管理客户端Studio 等永远通过 Discovery API 与稳定的 ID 契约来使用它们。在实现层面你可以从 OutputConverterRegistry.cs、Endpoint.cs 以及组件/单元测试如 OutputConverterApiClientTests.cs、OutputConverterEndpointTests.cs、OutputConverterRegistryTests.cs入手进一步验证这套服务端拥有的发现机制如何在真实请求与定义物化流程中生效。赞分享后端工作流自动化流程编排低代码【免费下载链接】elsa-coreThe Workflow Engine for .NET项目地址https://gitcode.com/gh_mirrors/el/elsa-core点击查看免费下载相关推荐OpenAPI服务发现终极指南微服务注册发现的API描述规范OpenAPI服务发现终极指南微服务注册发现的API描述规范 OpenAPI规范OAS是一种标准化的API描述格式它定义了一种与语言无关的接口允许人类API设计文档后端Elsa Workflows 输出转换器Output Converter的显式稳定身份设计Converter ID、注册约束与运行时校验体系Elsa Workflows 输出转换器Output Converter的显式稳定身份设计Converter ID、注册约束与运行时校验体系 导读 本文以后端工作流自动化流程编排低代码Kratos Discovery Registry 接入指南基于 bilibili/discovery 的服务注册与发现Kratos Discovery Registry 接入指南基于 bilibili/discovery 的服务注册与发现 导读 contrib/registr后端微服务RPC框架Web框架云原生创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表