- 后端
- 工作流自动化
- 流程编排
- 低代码
【免费下载链接】elsa-core
The Workflow Engine for .NET
导读
本文围绕 elsa-core 仓库整合计划中的Paired Blazor host and source debugging方案展开,讲解如何在一个一次性的聚焦解决方案中,将 Core 的 Elsa 项目与后端Elsa.WorkflowContexts、Studio 端Elsa.Studio.WorkflowContexts两个真实模块以项目引用方式编译进同一个可运行的 Blazor 主机,随后用 NetCoreDbg 在后端接口与Razor 组件回调两侧打真实源码断点,验证 WorkflowContexts 的 Synthetic 复选框从选择到反选的全链路行为。读完本文,你将掌握这套"源码钉住(source-pinned)的可复现开发证据"的准备命令、运行约束、序列化类型注册契约、断点命令文件语义,以及它相对完整整合解决方案的边界与证据含义。
前置:先产出配对的源码契约探针结果
配对 Blazor 主机不是一个独立步骤,它强依赖于先运行成功的 配对 WorkflowContexts 源码契约探针。该探针(Program #8194、feature #8215、story #8279、task #8280/#8284)用一次性构造的 harness 以项目引用方式把后端与 Studio 的 WorkflowContexts 模块编进 Core 与 Studio,验证 Studio 的RemoteFeature名称与后端已安装功能注册表一致,然后通过真实 API 客户端与后端接口在 loopback HTTP 上调用 Studio 的RemoteWorkflowContextsProvider,要求合成提供者恰好返回一次Synthetic描述符。其可复现命令为:
python3 scripts/integration-program/run_paired_source_probe.py \ --core-source /path/to/elsa-core \ --extensions-source /path/to/elsa-extensions \ --studio-source /path/to/elsa-studio \ --output /path/to/new-disposable-proof探针需要 .NET 10 与三个仓库的精确提交(Core22f479d4...、Extensions33fa0bfd...、Studio9afd3e36...),输出目录必须不存在;脚本会创建本地共享 Git 克隆并检出精确提交,不改变调用方源码。探针同时处理了 Extensions Studio 模块中一处导致编译失败的未使用@using Blazored.FluentValidation(在一次性克隆中删除该行并记录前后哈希,这是显式的兼容性修正,并非上游改动)。Blazor 主机准备脚本正是读取这份探针的evidence.json、build.log与钉住的源码状态作为准入前提。
一、准备工作:从契约收据到聚焦解决方案
1.1 准备命令与产物
在探针成功产出契约后,运行准备脚本生成聚焦的解决方案与主机:
python3 scripts/integration-program/prepare_paired_blazor_host.py \ --proof-output /path/to/new-disposable-proof cd /path/to/new-disposable-proof/UiProbe dotnet run --no-build --project UiProbe.csproj脚本(prepare_paired_blazor_host.py)会在探针输出目录内创建PairedDevelopment.sln与UiProbe主机,并依次执行三条dotnet命令(源码第 74-76 行):dotnet new sln --format sln --name PairedDevelopment、dotnet sln ... add(把UiProbe/UiProbe.csproj、elsa-core/src/modules/Elsa/Elsa.csproj、elsa-extensions/src/modules/workflows/Elsa.WorkflowContexts/Elsa.WorkflowContexts.csproj、elsa-extensions/src/modules/workflows/Elsa.Studio.WorkflowContexts/Elsa.Studio.WorkflowContexts.csproj四个项目加入)、dotnet build ... -p:TargetFramework=net10.0 -p:UseProjectReferences=true --verbosity quiet,即以net10构建含项目引用依赖闭包的聚焦解决方案。这是聚焦的开发解决方案,并不代表整个整合后的 Elsa 解决方案已完整可构建。
UiProbe.csproj本身(UiProbe.csproj)可见三个项目引用(Elsa、Elsa.WorkflowContexts、Elsa.Studio.WorkflowContexts)外加以Compile Include方式链接的ContractProbe/HttpProbe.cs,并关闭了打包能力(IsPackable=false)。
1.2 准备脚本的四类硬性检查
从prepare_paired_blazor_host.py的validate_source_proof与validate_build_environment(源码第 22-51 行)可以看出,准备阶段不是简单的文件复制,而是对探针结果做全量复核:
- 精确源码钉:
receipt['sourceCommits']必须与三个仓库的钉住提交完全一致,且git rev-parse HEAD与git status --porcelain(含 untracked)必须与探针结束时一致,不允许出现源码漂移; - 完整提供者身份:探针结果必须满足
providerTypeResolves、featureMatches、httpRoundtrip全为 true,描述符计数为 1、名称为Synthetic、类型为SyntheticWorkflowContextProvider, ContractProbe; - 声明式导入补丁:
evidence.json中的sourcePatch必须与基线文件经patched_import_bytes变换后的哈希一致,即那份@using Blazored.FluentValidation删除补丁必须被保留且未被改动; - 拒绝环境配置干扰:在探针输出目录及其所有祖先目录中,任何名为
directory.build.props、directory.packages.props、global.json、nuget.config、msbuild.rsp等环境级构建配置都会导致ValueError("Ambient build configuration is not permitted"),并要求改用干净的 disposable 目录;同时共享契约源ContractProbe/HttpProbe.cs必须与受评审的 fixture 逐字节一致且不得是符号链接。
失败/中断的幂等性由prepare的 try/except(源码第 91-96 行)保证:只删除本次新建的UiProbe与PairedDevelopment.sln,保留blazor-build.log与源码克隆,允许重试;对已存在的主机或解决方案则直接拒绝覆盖。命令有15 分钟超时,并通过 POSIX 进程组自行清理(start_new_session=True+killpg)。构建结束后脚本会再次执行两类校验并打印 JSON 摘要,其中browserVerified与interactiveDebuggingVerified固定为false——构建成功本身不代表浏览器或调试器验证已通过。
对应的 9 个聚焦测试(test_paired_blazor_host.py)覆盖了:接受已验证源码但拒绝 untracked 漂移、拒绝错误钉或未解析提供者、即使 git 状态相同也拒绝被改动的导入、拒绝伪造的补丁收据与不匹配的探针输出、拒绝根目录/父目录构建配置、拒绝被修改的共享契约源、以及失败后仅清理新建输出且可重试。
1.3 这是一个"钉住源码的开发证明",而非隔离构建
原文档明确强调:这是 source-pinned 开发者证明,不是hermetic build,也不是沙箱。它信任已安装的 SDK、进程环境与用户级 NuGet 配置/缓存,目录守卫并不能中和这些宿主输入。因此应使用可信的开发账户,并在比较结果时记录相关的 SDK/feed 覆盖项;发布级的可复现性检查需要在受控的打包工作流中单独运行。
二、浏览器验证:Synthetic 复选框的往返契约
2.1 启动与期望行为
主机绑定 loopback,访问http://127.0.0.1:6187。若端口被占用,应先停止之前的 disposable probe,不要终止无关的监听进程。页面渲染的是真实的WorkflowContextsEditor组件,其提供者数据来自真实后端接口(http://127.0.0.1:6187/elsa/api,通过ProbeBackendClient连接)。Blazor 电路(Interactive Server 渲染模式,见 Probe.razor 的@rendermode InteractiveServer)连接后,Synthetic 复选框初始为未选中、更新计数为 0。
选中 Synthetic 后,页面#properties预格式化区域必须显示:
{"Elsa:WorkflowContextProviderTypes":["SyntheticWorkflowContextProvider, UiProbe"]}回调计数(updates)必须变为 1;反选后类型列表清空([]),计数变为 2。整个过程中不保存任何数据库或工作流——该示例刻意将合成数据保存在内存中。
2.2 主机代码如何满足契约
Program.cs 完整展示了这一定向配置:
- 拒绝外来 Kestrel 端点:启动即检查
builder.Configuration.GetSection("Kestrel:Endpoints").Exists(),存在则抛出InvalidOperationException("This disposable loopback probe does not accept configured Kestrel endpoints."),随后以UseUrls("http://127.0.0.1:6187")强制绑定 loopback; - 合成权限身份:中间件为当前上下文构造仅含
read:workflow-context-provider-descriptors权限的本地 ClaimsPrincipal,仅供本地演示,不构成生产授权或租户隔离; - 序列化类型注册(关键契约,见下文第三节):
Configure<SerializationTypeOptions>(o => o.RegisterTypeAlias(typeof(SyntheticWorkflowContextProvider), ...GetSimpleAssemblyQualifiedName())); - 真实模块装配:
AddElsa(elsa => elsa.UseWorkflowContexts())安装后端功能,AddFastEndpoints仅从WorkflowContextsFeature程序集自动发现端点,并注册 Studio 侧RemoteWorkflowContextsProvider为IWorkflowContextsProvider; - 提供者单例
SyntheticWorkflowContextProvider同时注册到 Core 契约IWorkflowContextProvider,保证后端接口能返回该描述符。
三、核心兼容点:序列化类型标识与UnregisteredClrType
这是整个方案的"隐藏难点"。从 paired-source-probe.md 与 Elsa.Common 源码可知:钉住的 Core 序列化器对未注册类型会刻意输出UnregisteredClrType:元数据,而 Extensions 当前的 WorkflowContexts 加载器仍期望一个简单的程序集限定名。因此主机必须用该标识在SerializationTypeOptions中显式注册受信任的提供者。
SerializationTypeOptions.cs 定义了这一机制:构造器中预置了一大批内置别名(Int32、String、Boolean、JSON之于ExpandoObject等,源码第 25-49 行),并暴露RegisterTypeAlias(Type, string)(写入AliasTypeDictionary与TypeAliasDictionary两个字典)与RegisterLegacyTypeName。配套的 SerializationTypeOptionsExtensions.cs 提供了AddTypeAlias<T>()、AddTypeAliasWithLegacyName、AddSimpleAssemblyQualifiedTypeAlias等便捷方法;SerializationTypeRegistry.cs 负责把这些别名装载进运行时的ISerializationTypeRegistry(TryGetType/TryGetAlias双向解析)。
本示例选择了RegisterTypeAlias+GetSimpleAssemblyQualifiedName()的组合,使序列化器对提供者类型输出SyntheticWorkflowContextProvider, UiProbe这一简单程序集限定名(与浏览器验证的 JSON 完全一致),既满足旧加载器,又不改变序列化器的安全边界——它不会授权解析任意调用方提供的 CLR 类型名。探针文档同时强调:校验时应断言完整返回的标识精确解析为已知的合成提供者类型,仅检查描述符显示名称是不够的。
四、双侧源码断点调试(NetCoreDbg)
4.1 使用钉住的调试器版本
按 paired-source-probe.md 使用已验证的调试器发布物与归档哈希(NetCoreDbg 3.2.0-1092;netcoredbg-osx-arm64.zip的 SHA-256 为f4fa33b3ff874910cc184b4bb3b9c56d0abdf5c6521cee0b144d7c6e4a6e59ea;可执行文件自报3.2.0-1 (9744e1f, Release))。无需全局安装调试器;使用前应自行核验下载工具的来源(harness 不会自动下载或执行调试器)。
从准备好的UiProbe目录,不使用dotnet run,而是:
/path/to/netcoredbg --interpreter=cli \ --command=/path/to/elsa-core/scripts/integration-program/paired-blazor-host/debug.commands \ -- dotnet bin/Debug/net10.0/UiProbe.dll4.2 命令文件语义与预期命中
debug.commands 内容如下,注意它遵循调试器同步 CLI 模式:
set just-my-code 0 break Elsa.WorkflowContexts.Endpoints.ProviderTypes.List.List.ExecuteAsync break WorkflowContextsEditor.razor.cs:50 run backtrace delete 1 continue backtrace delete 2 continue quit调试过程与预期严格对应:
- 主机开始监听后打开页面,调试器必须命中后端
List.ExecuteAsync断点并打印调用栈(Endpoint.cs:28);命令文件随后删除该断点并continue; - Blazor 电路连接后选中 Synthetic,必须命中Studio 组件回调
WorkflowContextsEditor.razor.cs:50(即OnCheckChanged,对应异步状态机MoveNext),打印组件回调栈、删除该断点并继续; - 浏览器随后显示预期类型标识与更新计数。这些是真实源码断点,不是日志标记。
命令文件使用同步 CLI 行为:run/continue之后不需要wait;在run后添加wait可能让命令无限等待。若手动执行卡住,应使用quit并确认一次性探针进程退出。已捕获的路径归一化转录 debug-transcript.txt 展示了后端与组件两个断点的命中栈帧及exited, exit-code: 0。
4.3 退出与清理
从启动终端用Ctrl+C停止主机;使用命令文件时,向显示的 disposable dotnet 进程发送优雅终止信号可让其退出、调试器执行quit。不要遗留处于暂停状态的主机或浏览器电路。
五、边界、证据与后续验收
5.1 明确的安全与部署边界
该示例:拒绝外部配置的 Kestrel 端点、仅对文档化命令绑定 loopback、安装合成权限身份做本地演示;不配置生产认证、租户授权或持久化工作流存储,因此不可部署。项目不可打包(nonpackable),准备脚本也没有 publish 或 vendor-API 路径。聚焦解决方案合并构建零错误,既有源码/依赖警告与本地克隆的 SourceLink 警告保留在blazor-build.log;本地源码调试与可发布的 SourceLink 是两种不同的证明。
5.2 已记录的证据(2026-09-23 根账号实测)
原文档与 observed-result.json 记录如下证据:聚焦解决方案构建 0 错误(29 警告);浏览器验证 selectedUpdates=1、deselectedUpdates=2,选中/反选后Elsa:WorkflowContextProviderTypes分别为["SyntheticWorkflowContextProvider, UiProbe"]与[];调试器验证 backendBreakpointHit、componentBreakpointHit、browserUpdateAfterContinue 均为 true,exitCode 0。此前一个完全相同的 disposable UI 主机也命中了 line50 的真实组件回调、恢复后完成浏览器元数据更新并以 exit0 退出,后端/服务源码断点则在 #8281 中独立记录。根账号还使用组合命令文件验证了完整链路。最终准备守卫修订版通过了正常与优化 Python 下的 9 个聚焦测试、对照探针输出与精确钉住的导入变换校验了保留收据、以 0 错误(39 警告)重建解决方案,并在启动前拒绝了注入的非 loopback Kestrel 端点(build-transcript.txt 单独保留该次较晚的检查)。
5.3 与完整解决方案的关系
需要警惕的是:构建输出本身不断言浏览器或调试器成功——准备器将两者均报告为未验证。在关闭 #8215/#8279 之前,必须在最终整合后的源码布局上重复这些检查;完整的解决方案构建与真实主机的安全配置,应与此 disposable 开发样本分开保留。它是有界的先驱证明,本身并不确立整合根解决方案、交互式 Studio 或调试器验收的能力。
小结
配对 Blazor 主机把"源码级双端断点 + 浏览器行为验证"固化成一个可复现、可审计的 15 分钟命令序列:先由配对契约探针钉住三仓库精确提交与单行导入补丁,再由准备脚本以四类硬性校验产出 net10 聚焦解决方案,随后浏览器断言 Synthetic 复选框的选择/反选契约,最后用 NetCoreDbg 在Endpoint.cs:28与WorkflowContextsEditor.razor.cs:50命中真实源码断点。其核心价值在于:把 WorkflowContexts 的序列化类型兼容问题(UnregisteredClrTypevs 简单程序集限定名)显式化为可执行的主机注册代码与断言,并为后续整合根解决方案的 UI/调试器验收提供了严格前置。
- 后端
- 工作流自动化
- 流程编排
- 低代码
【免费下载链接】elsa-core
The Workflow Engine for .NET
相关推荐
elsa-core 源码配对探针(Paired Source Probe):跨仓库集成契约验证与断点调试实战指南
elsa core 源码配对探针(Paired Source Probe):跨仓库集成契约验证与断点调试实战指南 本指南以 paired source prob
后端工作流自动化流程编排低代码国家中小学智慧教育平台电子课本下载工具:3分钟极速获取教学资源
国家中小学智慧教育平台电子课本下载工具:3分钟极速获取教学资源 国家中小学智慧教育平台电子课本下载工具是一款专为教育工作者设计的智能软件,它能够帮助您从官方教育
网页爬虫教育Orleans + Blazor 双宿主模型实战指南:Blazor Server 与 Blazor WebAssembly 示例深入解析
Orleans + Blazor 双宿主模型实战指南:Blazor Server 与 Blazor WebAssembly 示例深入解析 导读 本指南基于微软
后端微服务
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考