内容
# Bowire 示例
演示 [Bowire](https://github.com/Kuestenlogik/Bowire) 的示例应用程序 — ASP.NET Core 的交互式 API 浏览器。该仓库是跨协议的 **Harbor flagship**:一个共享的 **Harbor Control Center** 域([`harbor-demo/`](harbor-demo/))在每种协议中呈现 - 侧边比较 + 多协议 USP - 现正在重塑为每个协议的微服务(参见 [`harbor-demo/REDESIGN.md`](harbor-demo/REDESIGN.md))。
小型插件的“hello-world”演示**不**在这里 - 每个插件都移动到拥有该插件的仓库中([详细信息如下](#每个单独的插件演示现在位于哪里))。
## Harbor 演示
所有 harbor-demo 示例都共享一个 **Harbor Control Center** 域(`Ship`、`Dock`、`Crane`、`Container`、`PortCall`)来自 `Kuestenlogik.Bowire.Samples.Shared`,因此每种协议都讲述相同的故事,但具有不同的线格式。
| 示例 | 端口 | 显示 |
|---|---|---|
| **综合** | 5101 | gRPC + REST + SignalR + WebSocket + SSE 对抗一个 `HarborStore` - 多协议 USP |
| **Grpc** | 5110 | 所有四种 gRPC 调用类型(单向 / 服务器流 / 客户端流 / 双工),尾部,身份验证元数据 |
| **Rest** | 5111 | 完整的 HTTP 动词覆盖,`ProblemDetails`,多部分上传(`IFormFile`) |
| **SignalR** | 5112 | 调用,`IAsyncEnumerable<T>` 流,组,用户范围的广播 |
| **WebSocket** | 5113 | 文本 + 二进制帧,子协议协商,保持活动 |
| **Sse** | 5114 | `Last-Event-ID` 从 512 事件重放缓冲区恢复 |
| **GraphQL** | 5115 | HotChocolate 15 - 查询 + 变更 + 订阅,通过 `[ExtendObjectType]` 嵌套解析器 |
| **OData** | 5116 | OData v4 - `$select`,`$filter`,`$orderby`,`$expand`,`$count` 跨五个实体集 |
| **Mqtt** | 5117 (+ 1883 代理) | 嵌入式 `MqttServerFactory` 代理,保留消息,最后的遗嘱和 testament |
| **SocketIo** | 5118 | UI shell 仅(Socket.IO 需要 Node.js 代理 - 请参阅示例的 README) |
| **Mcp** | 5119 | AI 调用 `[McpServerTool]` + `[McpServerResource]` 通过 HTTP/SSE 传输 |
| **AsyncApi** | 5120 (+ Mqtt 示例的 1883 代理) | 模式驱动的发现 - 提供 `harbor-events.asyncapi.yaml`;Bowire 读取它并通过 AsyncAPI 插件将操作路由到 sibling Mqtt 示例的代理 |
另外 **`Kuestenlogik.Bowire.Samples.Shared`** - 常见的域类型 + 种子 `HarborStore`,包含 3 艘船,5 个码头,3 台起重机,6 个集装箱,3 个港口调用。其他每个项目都引用它。
## Harbor 微服务(重新设计中)
Harbor 演示正在从一个存储的整体中重塑为有界上下文的**微服务** - 每个域部分都在适合它的协议上,作为一个风景发现。参见
[`harbor-demo/REDESIGN.md`](harbor-demo/REDESIGN.md)。目前已经完成:
| 服务 | 上下文 | 协议 | 端口 |
|---|---|---|---|
| **舰队** | 船舶注册(主数据) | gRPC | 5150 |
| **库存** | 码头 + 起重机配置 | OData | 5151 |
| **闸门** | 集装箱闸门生命周期 | REST | 5152 |
| **港口调用** | 港口调用编排(BFF 超过舰队 + 库存 + 闸门) | GraphQL | 5153 |
| **跟踪** | 原始 AIS 位置入口 | WebSocket | 5154 |
| **操作** | 操作员控制台出口(消耗跟踪) | SignalR | 5155 |
| **到达** | 公共到达板(CQRS 读取模型) | SSE | 5156 |
| **遥测** | 起重机设备总线 + 其自己的 AsyncAPI 模式 | MQTT(代理:1883)+ AsyncAPI | 5157 |
| **助手** | AI 操作助手前面服务 | MCP | 5158 |
| **网关** | 所有服务的单个工作台(目录发现) | Bowire | 5159 |
`PortCalls` 是一个 BFF:单个 `portCall(id) { ship dock containers }` 查询
扩展到 Fleet(gRPC),Inventory(OData)和 Gate(REST)- 一个查询,三个
电线。实时级联显示刻意的 WS-vs-SignalR 对比:`Tracking`
是一个裸 WebSocket AIS 入口,`Operations` 用 SignalR 的
组/流/广播功能重新发出它,而 `Arrivals` 是可恢复的 SSE 读取模型。
`Telemetry` 运行一个嵌入式 MQTT 代理,用于实时起重机状态(实时
的 Crane 共享内核拆分的一半 - Inventory 拥有同一个
`CraneId` 上的静态配置)并提供其自己的 AsyncAPI 模式;`Assistant` 将整个
风景暴露为 MCP 工具,AI 代理可以调用。
**一键启动** - Aspire AppHost 启动整个风景(每个
服务在其固定的目录端口上)并为您提供日志的仪表板:
```bash
dotnet run --project harbor-demo/src/Kuestenlogik.Bowire.Samples.AppHost
```
然后在 `https://localhost:5159/bowire` 处浏览所有内容。
**相关时间线** -
[`harbor-demo/recordings/port-call-1.bowire-recording.json`](harbor-demo/recordings/port-call-1.bowire-recording.json)
捕获 **一个港口调用(ID 1,船舶 101“Nordstern”,码头 1,起重机 1)跨越
所有八个线路** - gRPC,OData,REST,GraphQL,WebSocket,SignalR,SSE,MQTT -
由相同的共享 ID 键控,因此时间线作为单个业务事件读取
跨越整个景观。使用 `bowire recording validate`
验证它,从工作台的录音轨道重放其单向步骤,或使用
`bowire mock --recording harbor-demo/recordings/port-call-1.bowire-recording.json`
重服记录的表面。
## 领域
```text
船舶 一艘船舶(集装箱 / 散货 / 油轮)
码头 一个泊位,可选地带有起重机
起重机 附属于码头,空闲 / 工作 / 维护 / 服务停止
集装箱 存储 / 加载 / 船上
港口调用 预定 -> 接近 -> 码头 -> 离开 -> 已完成 (或取消)
```
## 运行
首先构建所有内容:
```bash
dotnet build Bowire.Samples.slnx
```
然后启动任何示例并在 `/bowire` 处浏览 Bowire UI:
```bash
dotnet run --project src/Kuestenlogik.Bowire.Samples.Combined # https://localhost:5101/bowire
dotnet run --project src/Kuestenlogik.Bowire.Samples.Grpc # https://localhost:5110/bowire
dotnet run --project src/Kuestenlogik.Bowire.Samples.Rest # https://localhost:5111/bowire
dotnet run --project src/Kuestenlogik.Bowire.Samples.SignalR # https://localhost:5112/bowire
dotnet run --project src/Kuestenlogik.Bowire.Samples.WebSocket # https://localhost:5113/bowire
dotnet run --project src/Kuestenlogik.Bowire.Samples.Sse # https://localhost:5114/bowire
dotnet run --project src/Kuestenlogik.Bowire.Samples.GraphQL # https://localhost:5115/bowire
dotnet run --project src/Kuestenlogik.Bowire.Samples.OData # https://localhost:5116/bowire
dotnet run --project src/Kuestenlogik.Bowire.Samples.Mqtt # https://localhost:5117/bowire (代理在 :1883)
dotnet run --project src/Kuestenlogik.Bowire.Samples.SocketIo # https://localhost:5118/bowire
dotnet run --project src/Kuestenlogik.Bowire.Samples.Mcp # https://localhost:5119/bowire
```
## 先决条件:本地打包 Bowire
示例引用 `Kuestenlogik.Bowire` + `Kuestenlogik.Bowire.Protocol.*` 作为 **NuGet 包**,而不是 `ProjectReference`。附带的 `nuget.config` 连接了一个 `local` 源,位于 `../Bowire/artifacts/packages/`,每个项目的包版本都固定为 `0.9.4`。
要使用新版本重新打包,请更改下面的 `Version=` 并更新每个 csproj 中的 `PackageReference`:
```bash
cd ../Bowire
dotnet pack Kuestenlogik.Bowire.slnx -c Release -p:Version=0.9.4
```
## 每个示例的详细信息
每个示例目录都附带自己的 README,其中包含方法列表、最小可行性示例代码片段以及该协议特有的功能。
## 每个单独的插件演示现在位于哪里
这里不再有 `protocols/` 文件夹 - 每个单独的插件演示都移动到拥有该插件的仓库中,作为一个**组合**的服务器 + 嵌入式工作台示例:
- **Monorepo 协议** → 主 **Bowire** 仓库的 [`samples/`](https://github.com/Kuestenlogik/Bowire/tree/main/samples):HTTP/gRPC(Rest,gRPC,GraphQL,OData,JSON-RPC,SignalR,SSE,WebSocket,SOAP,MCP),消息代理(MQTT 自包含;NATS + Pulsar 及其自己的 `docker-compose.yml`),以及 Node.js Socket.IO 服务器(`samples/socketio-chat`)。
- **Sibling-plugin 协议** → 每个 `Bowire.Protocol.*` 仓库的自己的 `samples/` 文件夹(Akka,Amqp,Dis,Kafka,Surgewave,TacticalApi,Udp)。
每个 .NET 示例都提供其协议**和**挂载 `/bowire`,因此它兼作发现目标和托管演示。
(历史:从 `Kuestenlogik/Bowire/examples/` 迁移到 2026-06 以整合每个示例轴到一个仓库;然后在 2026-07 将单独的插件演示移动到其所属插件的仓库中作为组合的嵌入式示例,拆除了 `protocols/` 文件夹 - 此仓库现在仅保留 Harbor 主舰。)