WeixinBotSdk 1.3.0
dotnet add package WeixinBotSdk --version 1.3.0
NuGet\Install-Package WeixinBotSdk -Version 1.3.0
<PackageReference Include="WeixinBotSdk" Version="1.3.0" />
<PackageVersion Include="WeixinBotSdk" Version="1.3.0" />
<PackageReference Include="WeixinBotSdk" />
paket add WeixinBotSdk --version 1.3.0
#r "nuget: WeixinBotSdk, 1.3.0"
#:package WeixinBotSdk@1.3.0
#addin nuget:?package=WeixinBotSdk&version=1.3.0
#tool nuget:?package=WeixinBotSdk&version=1.3.0
WeixinBotSdk
微信 ilink bot 的 C# 客户端 SDK,支持 .NET 8、.NET 9、.NET 10。围绕「扫码登录 → 长轮询收消息 → 事件 → 回复/推送」提供统一门面 WeixinBotClient。
源码:Gitee
安装
dotnet add package WeixinBotSdk
或直接在 .csproj 中添加引用:
<PackageReference Include="WeixinBotSdk" Version="1.3.0" />
快速开始
完整示例参见 samples/。
首次运行(需扫码)
using WeixinBotSdk;
using WeixinBotSdk.Models;
using Microsoft.Extensions.Logging;
// 创建客户端并接入日志
var bot = new WeixinBotClient();
// 首次启动无保存的 token,进入登录流程
if (!bot.IsLoggedIn)
{
// 1. 获取二维码 URL
var qr = await bot.StartLoginAsync();
Console.WriteLine($"请用微信扫描:{qr.QrCodeUrl}");
// 2. 等待扫码确认(最长 8 分钟超时)
var result = await bot.FinishLoginAsync(qr.QrCode, TimeSpan.FromMinutes(8));
if (!result.Connected && !result.AlreadyConnected)
{
Console.WriteLine("登录失败。");
return;
}
}
// 3. 启动长轮询,后台收消息
await bot.StartAsync();
// 4. 订阅消息事件(含媒体类型解析)
bot.MessageReceivedAsync += async e =>
{
if (e.ContentType == (int)MessageItemType.File)
{
await CdnDownloader.DownloadToFileAsync(
bot.GetEffectiveCdnBaseUrl(), e.DownloadEncryptedQueryParam!, e.AesKeyHex!,
Path.Combine("/tmp", e.FileName!));
}
else
{
Console.WriteLine($"[{e.From}] {e.Body}");
}
};
// ... 程序保持运行 ...
// 5. 退出前释放资源
await bot.StopAsync();
await bot.DisposeAsync();
后续运行(已有 token)
var bot = new WeixinBotClient();
bot.CdnBaseUrl = "https://your-cdn-domain.com"; // 设置 CDN 地址用于下载收到的媒体文件
await bot.StartAsync(); // 自动加载已保存的凭据,直接启动
bot.MessageReceived += (_, e) => Console.WriteLine(e.Body);
发送消息
以下调用通常在 MessageReceived 事件处理器(上文第 4 步的 e)中执行:
// 回复收到的用户(context_token 已由 SDK 自动缓存并自动回传)
await bot.SendTextAsync(e.From, "你好,我是机器人!");
// 文件附件(自动 AES-128-ECB 加密 → CDN 上传 → 发送)
await bot.SendFileAsync(e.From, "/path/to/report.pdf", fileName: "report.pdf");
// 图片 / 视频
await bot.SendImageAsync(e.From, "/path/to/photo.jpg");
await bot.SendVideoAsync(e.From, "/path/to/video.mp4");
context_token 全自动管理:用户发来消息时 SDK 自动提取并缓存
context_token,发送回复时无需传入,SDK 会自动附带。SeedContextToken仅用于测试或无历史对话的特殊场景。
关键 API
| 方法 | 说明 |
|---|---|
StartLoginAsync() |
获取二维码 URL |
FinishLoginAsync(qrcode, timeout) |
等待扫码确认并登录 |
StartAsync() |
加载保存的 token 并启动长轮询 |
StopAsync() |
停止长轮询 |
SendTextAsync(to, content, contextToken?) |
发送文本消息 |
SendImageAsync(to, filePath, contextToken?) |
发送图片(自动上传 CDN) |
SendVideoAsync(to, filePath, contextToken?) |
发送视频(自动上传 CDN) |
SendFileAsync(to, filePath, fileName?, contextToken?) |
发送文件附件(自动上传 CDN) |
SendTypingAsync(to, status) |
输入中状态(1=输入中,2=取消) |
SeedContextToken(to, token) |
预置用户会话 token(用于主动推送无历史对话的用户) |
事件
| 事件 | 说明 |
|---|---|
MessageReceived |
收到新消息时同步触发 |
MessageReceivedAsync |
收到新消息时异步触发(轮询循环内 await,适合回复/下载) |
StateChanged |
监控循环状态变化(Stopped/Running/Paused/Reconnecting) |
Token 过期
长轮询收到 errcode / ret = -14 时,SDK 进入 MonitorState.Paused,暂停 120s 后再试,不会自动重新扫码。token 仍无效会再次暂停。
订阅 StateChanged,在 Paused 时停轮询并重新登录。不要在事件处理函数里直接 await StopAsync()(会与轮询线程死锁),先让事件返回:
bot.StateChanged += (_, state) =>
{
if (state == MonitorState.Paused)
_ = ReloginAsync();
};
async Task ReloginAsync()
{
await bot.StopAsync();
var qr = await bot.StartLoginAsync();
Console.WriteLine($"Token 已过期,请重新扫码:{qr.QrCodeUrl}");
var result = await bot.FinishLoginAsync(qr.QrCode, TimeSpan.FromMinutes(8));
if (!result.Connected && !result.AlreadyConnected) return;
await bot.StartAsync();
}
凭据存储(IAccountStore)
登录成功后 SDK 把 AccountData(Token / BaseUrl / UserId / AccountId)写入存储;StartAsync 从中读取。默认是 JsonAccountStore(~/.weixinbot/accounts.json)。
换路径:
var bot = new WeixinBotClient(store: new JsonAccountStore("/var/lib/mybot/accounts.json"));
自定义后端(内存 / 数据库 / 密钥保管库):
public sealed class MyAccountStore : IAccountStore
{
public AccountData? Load() => LoadFromYourBackend(); // 无数据返回 null
public void Save(AccountData data) => PersistToYourBackend(data); // 扫码确认后覆盖
}
var bot = new WeixinBotClient(store: new MyAccountStore());
Load / Save 是同步调用,实现里不要长时间阻塞。
注意事项
- 网络失败:连续 3 次
getupdates失败 → 退避 30s 后重试。 - 事件订阅者:同步逻辑用
MessageReceived;异步回复/下载用MessageReceivedAsync(轮询循环内 await)。 - 媒体下载:收到图片、视频、文件等媒体消息时,SDK 自动解析 CDN 引用参数,通过
CdnDownloader.DownloadToFileAsync(bot.GetEffectiveCdnBaseUrl(), encryptedQueryParam, aesKeyHex, path)流式解密落盘。文件类型为MessageItemType.File(值为 4)。 - 发送约束:
from_user_id必须为空串""(非空会导致ret=-2 prepare failed,SDK 已统一处理);context_token为 null 时发送仍可成功,回复时自动回传缓存值。 - 媒体
aes_key编码:SDK 内部使用base64(hex 字符串)(与 openclaw-weixin 一致),请勿改为原始字节的 base64,否则对方无法解密媒体(显示「图片过期或被清理」)。
日志
SDK 各组件通过 ILogger 输出登录 / 轮询 / 收发 / 异常等日志:
using var loggerFactory = LoggerFactory.Create(b => b.AddConsole().SetMinimumLevel(LogLevel.Debug));
var bot = new WeixinBotClient(loggerFactory: loggerFactory);
日志前缀约定:
| 前缀 | 来源 | 说明 |
|---|---|---|
[AUTH] |
WeixinAuth | 扫码登录流程 |
[MON] |
WeixinMonitor | 长轮询启停、游标推进、令牌过期、失败退避 |
[HTTP] |
WeixinHttpClient | HTTP 请求/响应、host 重定向 |
[REPLY] |
WeixinBotClient | 消息发送及错误 |
更新日志
v1.3.0
- 修复 媒体发送(图片/视频/文件)回传
context_token,与文本路径一致 - 修复 CDN 上传 5xx 重试:每次重建
HttpContent,并正确设置 HTTP 状态码 - 修复 默认 CDN 地址不再写入缓存,避免挡住后续
getconfig的真实cdn_base_url - 修复
StartAsync改为await getconfig,去掉GetAwaiter().GetResult() - 新增
MessageItemType枚举(FILE=4,VIDEO=5);文档与示例不再把 FILE 写成 5 - 新增
MessageReceivedAsync:轮询循环内 await,适合异步回复/下载 - 新增 长轮询启停调用
notifystart/notifystop(失败仅记日志) - 新增 门面
Send*/ 登录方法支持CancellationToken;暴露State/StateChanged - 新增 媒体流式 AES 加解密(上传走临时密文文件,
DownloadToFileAsync边解密边写盘) - 变更
WeixinAuth/WeixinMonitor/WeixinClient/WeixinHttpClient改为 internal,公开入口仅为WeixinBotClient - 变更 未注入时由 SDK 创建的
HttpClient在DisposeAsync中释放 - 文档 Token 过期(
-14→Paused)处理方式、IAccountStore用法示例
v1.2.1
- 变更
samples/SendFilesDemo:移除硬编码的真实用户 ID 和本机文件路径,替换为占位值 - 优化
NUGET_README.md:精简示例项目表格,保留 GitHub 目录链接
v1.2.0
- 新增 媒体文件传输支持:
SendImageAsync/SendVideoAsync/SendFileAsync,自动完成 AES-128-ECB 加密 → CDN 上传 → 消息构造全流程 - 新增
CdnDownloader.DownloadAsync/DownloadToFileAsync:从 CDN 下载并解密收到的媒体文件 - 新增
IWeixinClient接口与WeixinClient实现类分离 - 增强
MessageReceivedEventArgs增加ContentType、FileName、FileSize、DownloadEncryptedQueryParam、AesKeyHex属性,方便订阅者处理 incoming 媒体消息 - 新增
CdnBaseUrl配置项,用于 CDN 地址全局配置
开源许可
Star & Follow
如果觉得有用,来 Gitee Star 支持下,或 Follow 获取更新。
| Product | Versions 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. |
-
net10.0
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.0)
-
net8.0
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.0)
-
net9.0
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.