ProtocolConversion.Protocol.SecsGem 0.1.1
ProtocolConversion — 协议转换库
基于 .NET 10 / C# 的协议转换类库:将一种协议的消息翻译转换为另一种协议的消息,以类库形式提供,可方便地集成到其他系统中。
支持协议:SECS/GEM(基于 Secs4Net)、HTTP、Rpc(gRPC), 支持通过 Redis / RabbitMQ 等发布订阅中间件进行跨进程消息传递,支持 EF Core + MySQL 消息流水存储,支持在一个进程中创建 多个转换实例。
需求对照
| 需求 | 实现 |
|---|---|
| 协议翻译(协议 A ↔ 协议 B) | 协议适配器 + 统一消息模型 ConversionMessage + 路由管道 |
| 以类库形式提供 | 多项目解决方案,NuGet 风格包结构 + DI 扩展 |
| 跨进程通讯(Redis、RabbitMQ 等发布订阅) | IMessageBus 抽象,独立扩展包 + Options 配置,新增中间件零侵入 |
| 翻译层支持用户按条件自定义翻译 | 翻译规则引擎:条件谓词 + 自定义翻译器 + 内置映射翻译器 |
| 支持 SECS/GEM、HTTP、Rpc | IProtocolAdapter 抽象 + 各协议独立适配器包 |
| 支持创建多个实例 | IProtocolConversionManager 实例管理器,实例间完全隔离 |
| 数据落地(来回数据可存储),EF + MySQL | EF Core + Pomelo MySQL,收/译/发/失败全阶段流水 |
架构
[协议A 端点] ──► AdapterA(收) ──► 翻译层(规则匹配) ──► MessageBus(跨进程发布/订阅) ──► AdapterB(发) ──► [协议B 端点]
│ │ │
└──────────── 消息流水存储(EF Core / MySQL)◄┘
Received / Translated / Sent / Failed 全阶段留痕
项目结构
ProtocolConversion.slnx
├── src/
│ ├── ProtocolConversion.Abstractions # 核心抽象:统一消息模型、适配器/总线/翻译/存储接口
│ ├── ProtocolConversion.Core # 翻译引擎、路由管道、实例管理器、DI 扩展、进程内总线/存储
│ ├── ProtocolConversion.Bus.Redis # Redis 发布订阅总线
│ ├── ProtocolConversion.Bus.RabbitMQ # RabbitMQ 发布订阅总线
│ ├── ProtocolConversion.Persistence.MySql # EF Core + MySQL 消息流水存储
│ ├── ProtocolConversion.Protocol.Http # HTTP 适配器(入站监听 / 出站调用)
│ ├── ProtocolConversion.Protocol.Rpc # gRPC 适配器(服务端 / 客户端)
│ └── ProtocolConversion.Protocol.SecsGem # SECS/GEM 适配器(Secs4Net,HSMS + SECS-II)
├── tests/ProtocolConversion.Tests # 单元测试与端到端测试
└── samples/
├── ProtocolConversion.Sample # HTTP 翻译 + 跨进程发布示例
└── ProtocolConversion.SecsGemSample # SECS/GEM 协议转换示例(含设备模拟器)
快速开始
1. 引入与注册
using ProtocolConversion.Core;
using ProtocolConversion.Core.Instances;
using ProtocolConversion.Protocol.Http;
using ProtocolConversion.Protocol.SecsGem;
using ProtocolConversion.Bus.Redis;
using ProtocolConversion.Persistence.MySql;
var services = new ServiceCollection();
services.AddProtocolConversion(); // 注册实例管理器
// 或自行创建:var manager = new ProtocolConversionManager();
2. 创建转换实例(HTTP → SECS/GEM 翻译示例)
var instance = await manager.CreateAsync("line-1", builder => builder
// 跨进程消息总线(Redis / RabbitMQ / 进程内)
.UseRedisBus(o => o.ConnectionString = "localhost:6379")
// 消息流水存储(EF Core + MySQL,收发数据全阶段落地)
.UseMySqlStore(o => o.ConnectionString = "Server=localhost;Database=protocol_conversion;User=root;Password=***;")
// 协议适配器
.AddHttpInbound("http-in", o => { o.ListenUrl = "http://localhost:8080"; o.Path = "/conversion"; })
.AddSecsGem("gem", o => { o.IpAddress = "127.0.0.1"; o.Port = 5000; o.IsActive = true; })
// 翻译路由:HTTP 请求 → 按条件翻译 → 发送到 SECS/GEM
.AddRoute("http-to-gem", "http-in", "gem", route => route
// 条件规则:按来源协议 / 消息头 / 负载任意条件匹配,首个命中生效
.When(
m => m.GetHeader("SECS.SF") == "S1F3",
new JsonFieldMappingTranslator(new Dictionary<string, string>
{
["$.lotId"] = "$.body.lot_no", // JSON 字段按路径搬移
["$.quantity"] = "$.body.qty",
}))
// 自定义翻译器(实现 IMessageTranslator)
.When(m => m.SourceProtocol == "SECS/GEM", new MySecsToHttpTranslator())
// 兜底翻译 + 未命中行为
.Use(new MyDefaultTranslator(), priority: 100)
.OnUnmatched(UnmatchedMessageBehavior.PassThrough))
// 跨进程路由:消息发布到总线主题(其他进程可订阅消费)
.AddRoute("http-to-bus", "http-in", "topic:converted-messages"));
await instance.StartAsync(); // 启动全部适配器并激活路由
3. 多实例管理
var instanceA = await manager.CreateAsync("line-a", builder => /* ... */);
var instanceB = await manager.CreateAsync("line-b", builder => /* ... */);
await manager.StartAllAsync();
await manager.DestroyAsync("line-a"); // 销毁实例
每个实例拥有独立的适配器、路由、总线通道与存储配置,实例之间互不影响。
核心概念
统一消息模型 ConversionMessage
所有协议消息都会被归一化为统一消息:
| 字段 | 说明 |
|---|---|
MessageId / CorrelationId |
消息标识 / 请求-应答关联标识 |
Direction |
Inbound(接收)/ Outbound(发送) |
SourceProtocol / TargetProtocol |
来源协议 / 目标协议 |
Headers |
协议元数据(HTTP 头、SECS S/F、RPC 信息等) |
Payload / PayloadText / PayloadAsJson() |
字节负载 / 文本 / JSON 访问 |
常用消息头前缀:http.header.*(HTTP 头)、SECS.Stream / SECS.Function / SECS.SF(SECS)、rpc.method(gRPC)。
协议适配器
| 适配器 | 扩展方法 | 说明 |
|---|---|---|
| HTTP 入站 | AddHttpInbound(name, o => ...) |
Kestrel 监听;请求/应答模式:翻译后的消息作为 HTTP 应答返回(超时返回 202) |
| HTTP 出站 | AddHttpOutbound(name, o => ...) |
发送 HTTP 请求;响应可再触发 MessageReceived 形成来回转换 |
| gRPC 入站 | AddGrpcInbound(name, o => ...) |
托管 gRPC 服务(Send 一元 / SendStream 双向流) |
| gRPC 出站 | AddGrpcOutbound(name, o => ...) |
通过 RPC 调用发送到远端服务 |
| SECS/GEM | AddSecsGem(name, o => ...) |
HSMS(SEMI E37)+ SECS-II;Primary 消息转入管道,应答(Secondary)自动回给对端 |
SECS/GEM 负载编码:默认为 JSON 项树({"format":"ASCII","value":"..."}、{"format":"List","items":[...]}),
便于其他协议直接消费 SECS 数据;设置 UseSmlPayload = true 可使用 SML 文本编码。
SECS 与统一消息的互转由 SecsMessageConverter 完成,可在自定义翻译中直接复用。
消息总线(跨进程发布/订阅)
路由端点写成 topic:主题名 即为总线端点,例如:
.AddRoute("a", "http-in", "topic:orders") // 发布到总线
.AddRoute("b", "topic:orders", "gem") // 从总线订阅
| 总线 | 扩展方法 | 说明 |
|---|---|---|
| Redis | UseRedisBus(o => ...) / AddRedisMessageBus(...) |
PUB/SUB,可配置频道前缀 |
| RabbitMQ | UseRabbitMqBus(o => ...) / AddRabbitMqMessageBus(...) |
topic 交换机,每个订阅者独立队列 |
| 进程内 | new InMemoryMessageBus() |
单进程部署 / 开发调试 / 测试 |
新增其他中间件:实现 IMessageBus 两个方法(PublishAsync / SubscribeAsync)并提供扩展方法即可,核心库零改动。
翻译层
规则按 Priority 升序匹配,首个命中生效:
.AddRoute("r", "in", "out", route => route
// 条件 + 自定义翻译器(实现 IMessageTranslator)
.When(m => m.SourceProtocol == "SECS/GEM", new MyTranslator(), priority: 0)
// 条件 + 委托
.When(m => m.GetHeader("KIND") == "A", m => m.WithPayload("..."u8.ToArray()))
// 兜底
.Use(new DefaultTranslator(), priority: 100)
// 未命中行为:PassThrough(透传)/ Drop(丢弃)/ Error(记失败)
.OnUnmatched(UnmatchedMessageBehavior.PassThrough));
也可以用 Rule.When(...) 构建独立规则对象复用:
var rule = Rule.WhenHeader("SECS.SF", "S1F3")
.WithPriority(10)
.TranslateUsing(new MyTranslator())
.Build();
内置翻译器:
JsonFieldMappingTranslator— JSON 字段按路径搬移("$.lotId" → "$.body.lot_no")HeaderMappingTranslator— 消息头改名映射DelegateTranslator— 委托包装
自定义翻译器:实现 IMessageTranslator.TranslateAsync 即可,可注入任意服务(数据库、规则引擎、AI 服务等)。
错误应答:翻译/转发失败时,若消息需要应答(CorrelationId 存在且来源为适配器),
管道会向请求方回发带 conversion.error 消息头的错误应答(HTTP 返回 500 + 错误详情),避免调用方等待超时。
消息流水存储(EF Core + MySQL)
.UseMySqlStore(o => o.ConnectionString = "Server=localhost;Database=protocol_conversion;User=root;Password=***;")
// 或 services.AddMySqlMessageStore(o => ...);
- 管道的 Received / Translated / Sent / Failed 各阶段均写入
conversion_messages表 - 默认自动建表(
AutoCreateSchema),可通过ServerVersion指定 MySQL 版本 - 查询接口
IMessageStore.QueryAsync(MessageQuery):按实例、路由、消息 ID、关联 ID、阶段、来源协议、时间范围过滤 - 接入其他数据库:实现
IMessageStore或复用ConversionDbContext(换任意 EF Core Provider)
扩展指南
| 扩展点 | 接口 | 接入方式 |
|---|---|---|
| 新协议 | IProtocolAdapter(可继承 ProtocolAdapterBase) |
新建适配器包 + AddXxx(...) 扩展方法 |
| 新消息中间件 | IMessageBus |
新建总线包 + UseXxxBus(...) 扩展方法 |
| 自定义翻译 | IMessageTranslator / ITranslationRule |
注册到路由规则 |
| 新存储 | IMessageStore |
UseMessageStore(...) 或 DI 注册 |
示例与测试
示例 1:HTTP ↔ 翻译 ↔ 跨进程发布(samples/ProtocolConversion.Sample)
# 运行示例(默认 HTTP :8080,可用环境变量覆盖配置)
dotnet run --project samples/ProtocolConversion.Sample
# 发送测试请求
curl -X POST http://localhost:8080/conversion \
-H "Content-Type: application/json" \
-d '{"lotId":"LOT-1","quantity":5}'
# 应答:{"lotId":"LOT-1","quantity":5,"body":{"lot_no":"LOT-1","qty":5}}
示例支持通过 appsettings.json 或环境变量(Conversion__Http__ListenUrl、Conversion__MySql__ConnectionString、
Conversion__Redis__ConnectionString 等)配置 MySQL、Redis / RabbitMQ 与目标地址;
未配置外部服务时自动使用进程内总线与存储,开箱即用。
示例 2:SECS/GEM 协议转换(samples/ProtocolConversion.SecsGemSample)
完整演示 HTTP ↔ SECS/GEM 双向翻译,内置 设备模拟器(HSMS 被动方),无需真实设备即可运行:
HTTP 客户端 ──JSON──► HTTP 入站 ──翻译──► SECS/GEM 适配器 ──HSMS──► 设备模拟器
HTTP 客户端 ◄─JSON── HTTP 应答 ◄─翻译── SECS/GEM 适配器 ◄─S1F4── 设备模拟器
设备模拟器 ──S6F11 事件──► 适配器 ──翻译──► 总线主题 topic:secs.events(跨进程)
设备模拟器 ──S1F1 请求──► 转换管道自动应答 S1F2(设备发起的请求同样被转换处理)
# 启动(设备模拟器 + 转换实例,默认 HTTP :8081、HSMS :5000)
dotnet run --project samples/ProtocolConversion.SecsGemSample
# 查询设备状态(业务语义写法:{"svids":[...]})
curl -X POST http://localhost:8081/secs -H "Content-Type: application/json" \
-d '{"svids":[1,2,3]}'
# 应答:{"sf":"S1F4","data":{"format":"L","items":[{"format":"U4","value":[2]},{"format":"F8","value":[28.78]},{"format":"A","value":"LOT-083"}]}}
# 查询设备状态(SECS 协议写法:直接指定 S/F 与项树)
curl -X POST http://localhost:8081/secs -H "Content-Type: application/json" \
-d '{"sf":"S1F3","item":{"format":"L","items":[{"format":"U4","value":[1,2,3]}]}}'
# 查询设备常量(S2F13 → S2F14)
curl -X POST http://localhost:8081/secs -H "Content-Type: application/json" \
-d '{"sf":"S2F13","item":{"format":"L","items":[{"format":"U2","value":[1,2]}]}}'
# AreYouThere(S1F1 → S1F2)
curl -X POST http://localhost:8081/secs -H "Content-Type: application/json" \
-d '{"sf":"S1F1","item":{"format":"L","items":[]}}'
该示例演示的翻译层能力:
| 翻译器 | 作用 |
|---|---|
FindSvidRequestTranslator |
业务语义 JSON {"svids":[...]} → SECS S1F3(条件规则优先匹配) |
JsonToSecsTranslator |
通用协议 JSON {"sf":"S1F3","item":{...}} → SECS 消息 |
SecsToJsonTranslator |
SECS 消息(含设备事件)→ 业务 JSON |
AreYouThereAckTranslator |
设备 S1F1 → 自动应答 S1F2(Primary Message 应答路由) |
收发数据的来回全过程写入消息流水存储;配置 SecsGemSample__Redis__ConnectionString 可切换为 Redis 跨进程总线,
配置 SecsGemSample__MySql__ConnectionString 可切换为 MySQL 存储,SecsGemSample__LogLevel=Debug 可查看 SECS 报文细节。
运行测试
dotnet test tests/ProtocolConversion.Tests
打包发布(NuGet Package)
本库以 NuGet 包形式提供给其他系统集成:每个功能包独立打包,另提供元包
ProtocolConversion 一键引入全部能力(安装元包即传递引入所有子包)。
| 包名 | 内容 |
|---|---|
ProtocolConversion |
元包:安装即包含以下全部功能 |
ProtocolConversion.Abstractions |
统一消息模型与核心接口 |
ProtocolConversion.Core |
翻译引擎、路由管道、多实例管理器、DI 扩展 |
ProtocolConversion.Protocol.SecsGem |
SECS/GEM 适配器(Secs4Net) |
ProtocolConversion.Protocol.Http |
HTTP 适配器 |
ProtocolConversion.Protocol.Rpc |
gRPC 适配器 |
ProtocolConversion.Bus.Redis |
Redis 发布订阅总线 |
ProtocolConversion.Bus.RabbitMQ |
RabbitMQ 发布订阅总线 |
ProtocolConversion.Persistence.MySql |
EF Core + MySQL 消息流水存储 |
构建与打包
# 打包(生成 nupkg + snupkg 符号包到 artifacts/)
dotnet pack ProtocolConversion.slnx -c Release -o artifacts
# 指定版本号打包
dotnet pack ProtocolConversion.slnx -c Release -o artifacts -p:PackageVersion=1.2.0
版本号在 Directory.Build.props 的 <VersionPrefix> 统一维护;包元数据(作者、标签、
README、XML 文档)同样在 Directory.Build.props 中集中配置。
发布到 NuGet 仓库
# 发布到内网 NuGet 源(如 Azure Artifacts / NuGet.Server / BaGet 等)
dotnet nuget push artifacts/*.nupkg \
--source https://your-internal-feed/v3/index.json \
--api-key <YOUR_API_KEY>
其他系统如何使用
# 安装元包(获得全部功能)
dotnet add package ProtocolConversion
# 或按需只安装某个子包(如仅需 SECS/GEM 适配器)
dotnet add package ProtocolConversion.Protocol.SecsGem
using ProtocolConversion.Core;
using ProtocolConversion.Core.Instances;
services.AddProtocolConversion(); // 注册实例管理器,随后创建转换实例即可
提示:若内网仓库要求包许可证/仓库地址,可在
Directory.Build.props中补充<PackageLicenseExpression>、<RepositoryUrl>、<PackageProjectUrl>后重新打包。
技术栈
- .NET 10 / C#,
Microsoft.Extensions.*(DI / Options / Logging) - Secs4Net 3.1 + Secs4Net.Sml(SECS/GEM)
- Grpc.AspNetCore / Grpc.Net.Client(Rpc)
- StackExchange.Redis、RabbitMQ.Client 7(跨进程消息总线)
- Entity Framework Core 9 + Pomelo.EntityFrameworkCore.MySql(MySQL 存储)
- xUnit(测试)
Showing the top 20 packages that depend on ProtocolConversion.Protocol.SecsGem.
| Packages | Downloads |
|---|---|
|
ProtocolConversion
协议转换库(元包):将一种协议的消息翻译转换为另一种协议的消息。安装本包即包含全部功能:SECS/GEM(Secs4Net)、HTTP、Rpc(gRPC)协议适配器,Redis / RabbitMQ 跨进程发布订阅总线,EF Core + MySQL 消息流水存储,条件化翻译规则引擎与多实例管理。也可按需安装子包:ProtocolConversion.Protocol.SecsGem、ProtocolConversion.Protocol.Http、ProtocolConversion.Protocol.Rpc、ProtocolConversion.Bus.Redis、ProtocolConversion.Bus.RabbitMQ、ProtocolConversion.Persistence.MySql。
|
0 |
.NET 10.0
- ProtocolConversion.Core (>= 0.1.1)
- Secs4Net (>= 3.1.0)
- Secs4Net.Sml (>= 3.1.0)
| Version | Downloads | Last updated |
|---|---|---|
| 0.1.1 | 0 | 11/10/2026 |