C# 快速接入
使用 WuKongEasySDK-CSharp NuGet 正式包接入 .NET 8,完成认证、在线消息、自动重连和异步释放。
WuKongEasySDK-CSharp 参考 JavaScript EasySDK 的 WebSocket JSON-RPC 协议,提供符合 C# 习惯的异步 API 和强类型事件。运行时不依赖第三方包。
NuGet 正式版 1.0.0
WuKongEasySDK 1.0.0 已发布到 nuget.org,对应源码 02ea7d60cd94feef1996f41bca35ffc3b8e18ea6。下文默认使用公共 NuGet 安装;源码引用与本地打包用于需要自行构建的场景。
开始前
- 准备 .NET 8 或更新版本,以及 Windows、Linux 或 macOS 开发环境。当前目标框架为
net8.0,不包含 Unity、.NET Framework 和浏览器 WebAssembly 支持。 - 启动
/readyz健康的 WuKongIM 单节点集群或多节点集群,确认客户端可以访问 WebSocket Gateway。单节点集群同样遵循集群语义,默认使用 256 Hash Slots。 - 业务后端为 Alice 和 Bob 分别返回
uid、token和websocketUrl。客户端不调用/user/token或/route等 Product HTTP 管理接口。 - C# 默认使用 PC/Desktop
2。后端签发 Token 的device_flag必须与客户端一致;APP 为0,Web 为1。
先阅读 身份与 Token。生产环境使用 HTTPS/WSS,不关闭证书验证,不把 Token 放入 URL、日志或源码。
1. 安装 NuGet 正式包
dotnet new console -n MyChat --framework net8.0
dotnet add MyChat/MyChat.csproj package WuKongEasySDK --version 1.0.0 --source https://api.nuget.org/v3/index.json可选:从固定源码构建
git clone https://github.com/WuKongIM/WuKongEasySDK-CSharp.git
git -C WuKongEasySDK-CSharp checkout 02ea7d60cd94feef1996f41bca35ffc3b8e18ea6
dotnet new console -n MyChat --framework net8.0
dotnet add MyChat/MyChat.csproj reference WuKongEasySDK-CSharp/src/WuKongEasySDK/WuKongEasySDK.csproj两个目录处于同一级。将确切源码 revision 记录到构建配置,或通过固定 commit 的子模块维护引用。
如需本地 NuGet 安装,先在这个固定 checkout 中生成包:
cd WuKongEasySDK-CSharp
dotnet pack src/WuKongEasySDK -c Release -o artifacts
dotnet add ../MyChat/MyChat.csproj package WuKongEasySDK --version 1.0.0 --source ./artifacts公共包、项目引用和本地包三选一,不要同时引用。此处的 --source ./artifacts 指向你刚生成的本地源。
2. 由业务后端提供连接材料
登录业务系统后,通过受保护的业务接口取得:
{
"uid": "alice",
"token": "backend-issued-desktop-token",
"websocketUrl": "wss://im.example.com/ws"
}下面的控制台示例从 WUKONGIM_WS_URL、WUKONGIM_UID、WUKONGIM_TOKEN 环境变量读取这些值;桌面应用可以改为读取登录响应。它们是本示例的变量,不是服务端的 WK_ 配置项。
3. 连接、监听并发送
用下面代码替换 MyChat/Program.cs。启动前设置当前账号的三个环境变量,通过命令行参数传入对方 UID。
using WuKongEasySDK;
static string Required(string name) =>
Environment.GetEnvironmentVariable(name)
?? throw new InvalidOperationException($"Missing {name}");
if (args.Length != 1)
throw new ArgumentException("Pass the peer UID as the first argument.");
await using var im = new WKIM(Required("WUKONGIM_WS_URL"), new AuthOptions
{
Uid = Required("WUKONGIM_UID"),
Token = Required("WUKONGIM_TOKEN"),
DeviceFlag = DeviceFlag.Desktop
}, new WKIMOptions
{
ConnectTimeout = TimeSpan.FromSeconds(10),
RequestTimeout = TimeSpan.FromSeconds(15)
});
Action<RecvMessage> onMessage = message =>
{
// 按 MessageId 去重,并把 Payload 交给应用状态。
// WinForms/WPF 等 UI 需切回 UI 线程;不要打印完整消息。
Console.WriteLine("Message received.");
};
im.Message += onMessage;
im.Connected += _ => Console.WriteLine("Connected.");
im.Disconnected += _ => Console.WriteLine("Disconnected.");
im.Error += _ => Console.WriteLine("SDK operation failed.");
im.CustomEvent += notification =>
{
// 按 notification.Type 分发 notification.Data。
};
try
{
await im.ConnectAsync();
Console.WriteLine("Start the peer, then press Enter to send.");
Console.ReadLine();
var result = await im.SendAsync(args[0], ChannelType.Person,
new { type = 1, content = "Hello from C# 👋" });
if (!result.IsSuccess)
Console.WriteLine($"SEND rejected: {(int)result.ReasonCode}");
else
Console.WriteLine("Server accepted SEND.");
Console.WriteLine("Press Enter after checking both directions to exit.");
Console.ReadLine();
}
finally
{
im.Message -= onMessage;
await im.DisconnectAsync();
}两个终端分别使用 Alice/Bob 的连接材料,运行 dotnet run --project MyChat -- bob 和 dotnet run --project MyChat -- alice。异常会通过异步方法返回给调用者,后台错误也会触发 Error;应用应为认证失败、超时和业务拒绝分别提供处理界面。
库默认没有日志。只有显式设置 WKIMOptions.DebugLogger 才输出固定运行状态文本,不包含 Token、Payload、原始帧或服务端错误正文。
4. 群聊、发送结果与接收数据
群聊使用 ChannelType.Group 和业务后端管理的群 ID;成员关系和权限仍由服务端判定。可传入 SendOptions 设置 ClientMsgNo、Header、Setting 和 Topic。默认 Header 为 RedDot = true,显式传入的 Header 不会被 SDK 覆盖。
ReasonCode.Success 为 1。SendResult.IsSuccess 表示服务端接受了发送,不代表 Bob 已收到、已展示或已读。128–255 等业务拒绝码保留在结果中;JSON-RPC 错误抛出 WKIMRpcException,通过数字 Code 判定。
消息 ID 使用 string,数字形式的 ID 不经过浮点转换。MessageSeq 与 NodeId 为 ulong。消息 Timestamp 单位为 Unix 秒,自定义事件 Timestamp 为 Unix 毫秒。
RecvMessage.Payload 和 EventNotification.Data 为拥有独立生命周期的 JsonElement。接收 Payload 支持 JSON 对象和 Base64 JSON;无法解码的字符串保留原值。自定义事件的 JSON 字符串会解析为 JSON 值,普通字符串保持不变。
5. 重连、取消与释放
| 行为 | C# SDK 约定 |
|---|---|
| 实例所有权 | new WKIM / WKIM.Init 创建独立实例,无隐式全局单例 |
| 并发连接 | 多个 ConnectAsync 共享尝试;取消某个调用只停止其等待 |
| 停止共享连接 | 等待 DisconnectAsync 后才再次连接 |
| 初次失败 | 建连与认证共用 10 秒预算,失败直接返回 |
| 已连接后断线 | 默认最多重试 5 次,间隔 1、2、4、8、16 秒;成功后重置 |
| 停止自动重连 | 认证拒绝、服务端断开/踢下线、主动断开或释放 |
| 最终清理 | 在应用生命周期代码中等待 DisposeAsync,或使用 await using |
Token 更新或账号切换时,释放旧实例,再使用新的业务凭据创建客户端。需要跨进程保留设备 ID 时显式设置 AuthOptions.DeviceId。
事件在后台按顺序派发,回调必须尽快返回,不应阻塞等待 SDK 的异步操作或在回调内等待释放。单个监听器抛异常不会中断其他监听器和自动 ACK。已经入队的回调可能在移除监听或断开后继续执行;DisposeAsync 会等待它们结束。
RECVACK 表示消息进入 SDK 接收队列,不是业务处理确认。默认最多保留 256 个待完成请求、128 个待派发事件,单个完整 JSON-RPC 帧上限为 1 MiB。请求超限抛出 WKIMBackpressureException;事件队列满会关闭连接,不确认无法入队的消息。应用可以通过 WKIMOptions 调整这些边界。
SDK 不缓存离线消息,也不自动重发 SEND。请求超时、取消或断线时,发送可能已经成功。应用应先核对业务状态,需要重试同一条逻辑消息时复用 SendOptions.ClientMsgNo。离线恢复、会话、未读数、推送与业务回执由应用自行维护。
6. 运行官方示例和验收
在固定源码目录执行:
dotnet build -c Release
dotnet test -c Release
dotnet run --project examples/ConsoleChat -- bob控制台示例使用同样的环境变量,输入文本发送,/quit 或 Ctrl+C 退出。它把正文显示为聊天界面内容,不输出完整协议对象。
已有服务端二进制时,还可运行自动化真实进程测试:
WUKONGIM_BINARY=/absolute/path/to/wukongim python3 scripts/smoke.py该脚本只启动和清理自己拥有的回环地址单节点集群,使用 256 Hash Slots 并启用 Token 认证。它自动准备两个测试账号,检查双向 Unicode 消息的 SENDACK/RECV 一致性、重连、心跳和错误 Token 拒绝。
原始实现 d365a354f5e0f25fbd7f83bb59aa365ba43e899f 在 macOS arm64、.NET SDK 8.0.424 / runtime 8.0.30 通过 35 项测试、Release 构建与本地 NuGet 打包,并对 WuKongIM 132e46209d98fa0425cc0f88e7a97080cdad044d 完成上述真实进程验证。自定义事件与故障重连由回环 WebSocket 测试覆盖。此记录不包含公共 NuGet 下载、生产 WSS、离线恢复、多节点容量或长期稳定性验证。
NuGet 1.0.0 的独立发布验证覆盖 Windows、Linux、macOS 构建、35 项 SDK 测试、7 项发布校验测试与全新项目本地包安装。发布后从 nuget.org 下载精确版本,比较除 NuGet 签名外的全部包内容与测试产物,并在空包缓存、仅公共源的独立项目中完成还原、编译、加载和释放。此公共安装记录与上述真实服务端通信记录分别保留。
C# / JavaScript 真实互通
早期独立的 C#/JS 互通 CI 分别测试公共 NuGet WuKongEasySDK 1.0.0(空包缓存安装)与当前 C# 源码。固定对端为 npm easyjssdk 2.0.4、Node 24 + ws 8.21.3,服务端为 v3.0.0-beta.9 / 734166e0ec30fc0f6f10fef6f6d1889d079ab636。测试工具源码为 1db387c4f794a45bdb6f4e419d68dbe2bfef740f,与 NuGet 包源码分别记录。
五组场景覆盖双向中文/emoji 与嵌套自定义 Payload、超出 JavaScript 安全整数范围的消息 ID 及 SENDACK/RECV 一致性、错误 Token 拒绝、断网后自动重连、真实服务端崩溃重启,以及主动断开后拒绝离线 SEND 并允许显式重连。该服务端的 SENDACK 不返回 clientMsgNo,测试会校验 RECV 保留原始关联号。
上述早期复现记录的范围为 Node + ws。其中发现的 Node 原生 WebSocket 重连停滞,已在下面的独立源码修复与验收中处理。
Chromium/WSS 与原生 Node 恢复
早期扩展互通 CI分别使用正式 NuGet 1.0.0 和 C# 候选源码,验证 Node 24.3.0 原生 WebSocket,以及 Playwright 1.62.1 驱动的真实 Chromium。服务端仍固定为 734166e0ec30fc0f6f10fef6f6d1889d079ab636,JS 固定为修复源码 5e5dfb727fb0ea08294939962ae799e998b7ca5c。该修复结束只发出 error、没有后续 close 的握手失败,让有限次数重连继续执行;npm easyjssdk 2.0.4 不包含此修复。
浏览器从真实 HTTPS 页面建立 WSS 连接,C# 使用原有 ClientWebSocket。测试通过临时 CA 和隔离的浏览器 NSS 信任库保留正常证书校验,要求双方拒绝不受信任的 CA 和主机名不匹配的证书,且没有解密后的应用请求进入服务端协议。证书控制通过后,再执行双向消息、错误 Token、断网恢复、服务端重启和主动断开五组场景。
JS 修复已随 npm easyjssdk 2.0.5 正式发布,对应源码 b6d0bbe822b9c5b6f95a10d55b593d30184414f6。公共包互通 CI 从空缓存安装该固定 npm 包,六组正式 NuGet / C# 候选源码与 ws、原生 Node、Chromium WSS 的组合均通过,包含上述证书拒绝控制。
该单节点矩阵运行四条 Linux 任务,产生六份报告,记录 npm 下载地址及 SHA-512、实际测试提交、Chromium 版本和证书控制结果;复现与信任范围说明运行方法。这里验证的是临时 CA、回环 TLS 代理和 Chromium,不代表所有公网 CA、反向代理、Firefox/WebKit、多节点容量或长期稳定性。
三节点集群与应用切换地址
完整三节点故障恢复验收尚未通过,服务端迁移、恢复日志冲突和重启后漏收问题已记录在 Issue #927。本轮只处理 SDK、测试和文档;此前未合并的服务端实验不能作为已发布能力依据。上文已通过的单节点 WS/WSS 验证仍保留各自的精确版本和运行记录。
地址切换由应用负责。 一个 SDK 实例只有一个固定地址,自动重连仍访问该地址。业务后端选择存活入口并取得其 /route,客户端等待旧实例 DisposeAsync 完成,再使用新地址与原有凭据创建实例、注册事件并连接。中断中的 SEND 可能结果未知,不应自动重发已经确认或结果不明的消息。
三节点手动复现工具固定公共 NuGet WuKongEasySDK 1.0.0、npm easyjssdk 2.0.5、Node 24.3.0,服务端使用已发布的 v3.0.0-beta.9 源码 734166e0ec30fc0f6f10fef6f6d1889d079ab636。三个回环进程使用 256 Hash Slots、10 个逻辑 Slot 和三副本;测试覆盖入口间单聊/群聊、断线与离线发送拒绝、应用替换实例、节点重新加入,并严格检查 ACK/RECV 的关联和消息内容。节点上线、ISR 元数据齐全不等于物理副本已经追平。
常规 push/PR CI 运行四条单节点任务,产生六份 WS/原生 Node/Chromium WSS 报告。手动触发时选择 include_cluster=true 才追加两条三节点复现任务;遇到服务端阻塞会正常失败,不计为 SDK 三节点验收通过。本地运行命令为 python3 scripts/interop.py --transport native --topology three-node,候选源码增加 --candidate,并按工具说明提供精确服务端二进制。
复现工具记录服务端默认 90 秒在线路由租期引起的登录延迟,以及显式的迁移扫描预算。对已观察到的登录错误 15 有限重试是复现控制,不是重试所有系统错误或 SEND 的建议。完整三节点恢复、立即切换、多节点 WSS、离线同步、大群容量与长期稳定性均未由该工具建立保证。
下一步
查看 运行官方示例 和 SDK 验证记录,或回到 WuKongEasySDK 比较平台。生产接入继续参考 消息收发 与 集成验收。