WSHub.Abstractions 0.0.2

dotnet add package WSHub.Abstractions --version 0.0.2
                    
NuGet\Install-Package WSHub.Abstractions -Version 0.0.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="WSHub.Abstractions" Version="0.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="WSHub.Abstractions" Version="0.0.2" />
                    
Directory.Packages.props
<PackageReference Include="WSHub.Abstractions" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add WSHub.Abstractions --version 0.0.2
                    
#r "nuget: WSHub.Abstractions, 0.0.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package WSHub.Abstractions@0.0.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=WSHub.Abstractions&version=0.0.2
                    
Install as a Cake Addin
#tool nuget:?package=WSHub.Abstractions&version=0.0.2
                    
Install as a Cake Tool

WSHub

基于 .NET 的现代 WebSocket 即时通讯服务框架,参考并改进自 FreeIM。

职责清晰、可扩展、支持多节点部署,适用于游戏、IM、实时协作等场景。

.NET Version Tests License

特性

  • 发送与投递分离 — IMessageHandler(发送) + IMessageDeliveryHandler(投递)独立管道
  • 多节点支持 — 水平扩展,通过 Redis(FreeRedis)或 InMemory 进行消息路由
  • 后端语义一致 — InMemory 与 FreeRedis 共用同一套 ChannelBus 键、引用计数订阅/退订与本地投递语义,并由 RoomDemoFreeRedisE2ETests 在真实 Redis 上交叉验收
  • 多租户隔离 — 租户段由 Hub 强制注入总线键({prefix}:ch:{tenantId}:{channelId}),业务层无法绕过
  • 二进制消息 — byte[] 管道 + 路由头(0xFE),支持 protobuf
  • 连接收口 — ConnectionCloser 是断连与空闲回收的唯一路径:停发送队列 → 退频道 → 注销 presence → 关 socket
  • 活跃度保活 + 回板兜底 — 接收循环/心跳刷新 connIndex TTL;进程崩溃由宿主周期任务清理
  • 事件机制 — 上线/下线/断连/频道进出事件
  • 多目标框架 — net8.0 (LTS) / net9.0 / net10.0
  • Native AOT — InMemory 模式支持 Docker AOT 部署
  • 测试规模 — 662 个测试(单元 + Testcontainers/Redis 集成 + AOT 容器,详见 CI)

快速开始

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddWSHub<long>(options =>
{
    options.KeyPrefix = "wshub_v1";
    options.Servers = new[] { "localhost:5299" };
    options.Server = "localhost:5299";
})
.AddClientIdConverter<long, LongClientIdConverter>()
.UseInMemoryStorage<long>()       // 开发环境;生产用 .UseFreeRedisStorage(redis)
.AddDefaultHandlers<long>();      // 一键注册 Handler + Dispatcher + 后台服务

var app = builder.Build();
app.UseWebSockets();

app.Map("/ws/{tenantId?}", async (string? tenantId, HttpContext context) =>
{
    var handler = context.RequestServices.GetRequiredService<WebSocketConnectionHandler<long>>();
    await handler.HandleAsync(tenantId, context);
});

app.Run();

完整示例见 samples/MinimalApiSample/。

文档

文档 用途
docs/ARCHITECTURE-MAP.md 入口。架构对照稿 + 代码导航:设想 vs 现在的差异、冻结边界、键表、核对某条结论该看哪个文件
docs/ARCHITECTURE.md 规范性架构定义:边界、约束(C1–C6)、发布目标、Redis 键布局
docs/PROTOCOL.md 调用方契约:Control API、WebSocket 帧、202 语义、反模式
docs/DEMO-GAPS.md 做 RoomDemo 时实际撞到的 Hub 能力缺口(含 path 证据),下一步选型的输入

架构概览

客户端 WebSocket ──→ ProcessClientMessage ──→ MessageHandlerDispatcher ──→ IMessageHandler (发送)
                                                                                │
应用层主动发送 ──→ IApplicationMessageService ──→ MessageHandlerDispatcher ──→ IMessageHandler (发送)
                                                                                │
                                                                        IMessagePublisher
                                                                                │
                                                                    Redis / InMemory 消息总线
                                                                                │
                                                                        IMessageListener
                                                                                │
                                                                        HandleIncomingMessage
                                                                                │
                                                                        MessageDeliveryDispatcher ──→ IMessageDeliveryHandler (投递)
                                                                                                        │
                                                                                                ConnectionManager ──→ WebSocket

项目结构

WSHub/
├── src/
│   ├── WSHub.Abstractions/       # 接口、模型、Options
│   ├── WSHub.AspNetCore/         # ASP.NET Core 集成
│   ├── WSHub.Host/              # Control HTTP API 独立宿主
│   ├── WSHub.InMemory/           # InMemory 存储后端(开发/测试)
│   └── WSHub.FreeRedis/          # FreeRedis 存储后端(生产/多节点)
├── samples/
│   ├── MinimalApiSample/         # 基础示例 + 测试页面
│   ├── ImDemo/                   # ⚠ 绕开 Hub 的连接循环,仅作玩法参考
│   ├── GameDemo/                 # Protobuf HTML5 实时游戏
│   ├── RoomDemo/                 # 房间基础能力对照 + 可切 FreeRedis 后端的交叉验收
│   ├── RoomChatDemo/             # 多房间同时订阅 + 样例侧在线列表
│   ├── OfficialImDemo/           # 私聊/群聊走正式连接路径;历史显式标注为样例能力
│   └── AotDemo/                  # Native AOT Docker 部署示例
├── benchmarks/
│   └── WSHub.Benchmarks/         # BenchmarkDotNet 性能基准
├── tests/                        # 7 个测试项目,662 测试
├── docs/                         # 架构对照稿 + 架构规范 + 协议契约 + 性能分析
└── .github/workflows/            # CI/CD (coverage + publish + DingTalk)

性能 (BenchmarkDotNet)

操作 延迟 说明
PublishAsync 140 ns 单条消息发布
PublishBatchAsync ×100 13.9 μs 批量发布
RegisterAsync 1.08 μs / 248 B 连接注册
HasOnlineAsync 2.3 ns 在线检查

详见 docs/WSHub性能优化总结-1至10.md。

Samples

项目 说明
MinimalApiSample 基础 WebSocket + Channel + Broadcast
GameDemo Protobuf HTML5 多人实时游戏(手写 JS protobuf 编解码器)
RoomDemo 房间基础能力对照:走正式连接路径,重连补偿显式标注为样例行为;Storage:Backend=FreeRedis 可切生产后端做交叉验收
RoomChatDemo 一条连接同时订阅多个房间;样例侧「在线成员」是 GetOnlineClientIdsAsync 的近似,偏差由测试显式断言
OfficialImDemo 私聊 dm:{min}:{max} / 群聊走正式连接路径;好友与群成员校验在样例(403);内存历史标注为样例能力
ImDemo ⚠ 绕开 Hub(自建连接循环),只作业务玩法参考,不能用于验证 Hub 能力
AotDemo Native AOT + Docker 部署(docker compose up -d)

运行样例

dotnet run --project samples/RoomDemo          # http://localhost:5300
dotnet run --project samples/RoomChatDemo      # http://localhost:5500
dotnet run --project samples/OfficialImDemo    # http://localhost:5400
dotnet run --project samples/ImDemo            # http://localhost:5000 ⚠ 绕开 Hub,仅作玩法参考

多目标框架的样例(net8.0;net9.0;net10.0)必须显式指定框架,否则 dotnet run 报 Your project targets multiple frameworks:

dotnet run --project samples/GameDemo --framework net10.0           # http://localhost:5200
dotnet run --project samples/MinimalApiSample --framework net10.0   # http://localhost:5299

端口来自各自的 Properties/launchSettings.json,必须与 Program.cs 里的 options.Server / options.Servers 一致 —— 连接端点返回的 ws:// 地址就是按它拼的。

每个样例页面顶部都写了操作顺序(先连接,再进房/进会话,才收得到消息)。 只连上但没进房时,发送仍然返回 200,但 Hub 无从投递给你自己。

运行测试

dotnet test tests/WSHub.Abstractions.Tests/
dotnet test tests/WSHub.AspNetCore.Tests/
dotnet test tests/WSHub.InMemory.Tests/
dotnet test tests/WSHub.FreeRedis.Tests/
dotnet test tests/WSHub.IntegrationTests/
dotnet test tests/WSHub.Samples.Tests/      # 样例端到端(含 RoomDemo 的 FreeRedis 交叉验收)
dotnet test tests/WSHub.AotTests/           # 需要 Docker:构建 AOT 镜像并起容器

WSHub.Samples.Tests 里的 RoomDemoFreeRedisE2ETests 会起一个 redis:7-alpine Testcontainer, 用真实 Redis 把 RoomDemo 的「成员收到、非成员收不到」重跑一遍 —— 样例代码不变,只切 Storage:Backend。测试机上已有 Redis 时可设 REDIS_CONNECTION_STRING 复用,跳过启动容器。

运行 Benchmark

dotnet run -c Release --project benchmarks/WSHub.Benchmarks/

CI/CD

Workflow 触发 说明
coverage.yml push / PR 覆盖率报告 (dotnet-coverage)
publish-nuget.yml release / manual NuGet 发布 + 钉钉通知

贡献

欢迎提交 Issue 和 Pull Request。

License

MIT

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (3)

Showing the top 3 NuGet packages that depend on WSHub.Abstractions:

Package Downloads
WSHub.InMemory

In-memory storage backend for WSHub — suitable for development, testing, and single-pod deployments. Includes InMemoryConnectionRegistry, InMemoryTokenStore, and InMemoryMessageBus.

WSHub.AspNetCore

ASP.NET Core integration for WSHub — WebSocket connection handler, message dispatch pipeline (Send/Delivery separation), background services for Redis bus subscription, and minimal API endpoint support.

WSHub.FreeRedis

Redis storage backend for WSHub (FreeRedis-based) — suitable for production multi-pod deployments. Includes RedisConnectionRegistry, AggregatedMessageListener (refcount-based channel subscription), RedisMessagePublisher, and RedisTokenStore.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.0.2 91 10/1/2026
0.0.1 95 10/1/2026
0.0.0.41 192 8/11/2026
0.0.0.40 150 8/11/2026
0.0.0.39 153 8/8/2026
0.0.0.38 156 8/8/2026
0.0.0.37 165 8/8/2026
0.0.0.36 148 8/8/2026
0.0.0.35 154 8/8/2026
0.0.0.34 151 8/7/2026
0.0.0.33 203 8/5/2026
0.0.0.32 214 7/27/2026
0.0.0.31 164 7/27/2026
0.0.0.30 171 7/27/2026
0.0.0.29 160 7/26/2026
0.0.0.27 165 7/26/2026
0.0.0.26 167 7/26/2026
0.0.0.25 249 7/2/2026
0.0.0.24 176 7/1/2026
0.0.0.22 187 7/1/2026
Loading failed