Mud.Feishu
📖 简介
Mud.Feishu 是飞书服务端 SDK 的 .NET 适配版,提供完整的 HTTP API 客户端能力,支持 .NET Standard 2.0、.NET 6.0、.NET 8.0 和 .NET 10.0 平台。通过类型安全的 API 封装,让开发者能够在 .NET 应用程序中便捷、高效地集成飞书服务端功能。
✨ 核心特性
- 类型安全 - 强类型接口定义,编译时类型检查
- 模块化设计 - 按需注册 API 模块,减少不必要的依赖
- 自动令牌管理 - 智能缓存和刷新,无需手动维护
- 智能重试机制 - 内置重试策略,提高调用成功率
- 多应用支持 - 统一管理多个飞书应用
- 弹性策略 - Polly 重试 + 熔断,参数可按应用配置
- 配置热更新 -
BaseUrl/TimeOut等运行期生效,凭据变更即清库 - 原生 AOT 支持 - net8.0+ 一等公民支持 Native AOT 发布
- 完整 API 覆盖 - 支持组织架构、消息、群聊、审批、任务、云文档、画板、电子表格、多维表格、日历日程、视频会议、邮箱、AI、搜索、服务台等全部飞书核心功能
🏗️ 架构概览
graph TD
subgraph Mud_Feishu[Mud.Feishu]
direction TB
HTTP_API[HTTP API Client<br/>源生成客户端]
Token_Management[Token Management<br/>Smart Cache & Auto Refresh]
Module_Registry[Module Registry<br/>AddXxxApi / FeishuModule]
App_Manager[IFeishuAppManager<br/>多应用上下文]
HTTP_API --> Module_Registry
HTTP_API --> Token_Management
Module_Registry --> App_Manager
end
DataModels[Mud.Feishu.DataModels] --> HTTP_API
Abstractions[Mud.Feishu.Abstractions] --> Token_Management
HttpUtils[Mud.HttpUtils<br/>HTTP 客户端与弹性策略] --> HTTP_API
style Mud_Feishu fill:#e1f5ff
style HTTP_API fill:#4caf50,color:#fff
style Token_Management fill:#00bcd4,color:#fff
style Module_Registry fill:#9c27b0,color:#fff
style App_Manager fill:#ff9800,color:#fff🚀 快速开始
安装
dotnet add package Mud.Feishu💡
Mud.Feishu.Abstractions与Mud.Feishu.DataModels会作为依赖自动引入,通常无需单独安装。
服务注册
using Mud.Feishu;
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
// 注册飞书应用配置
builder.Services.AddFeishuApp(builder.Configuration);
// 方式一:懒人模式 - 注册所有 API 服务
builder.Services.CreateFeishuServicesBuilder()
.AddAllApis()
.Build();
// 方式二:建造者模式 - 按需注册
builder.Services.CreateFeishuServicesBuilder()
.AddOrganizationApi()
.AddMessageApi()
.AddChatGroupApi()
.AddApprovalApi()
.AddTaskApi()
.AddCardApi()
.AddAttendanceApi()
.AddDriveApi()
.AddWikiApi()
.AddDocxApi()
.AddSpreadsheetsApi()
.AddBiTableApi()
.AddCalendarApi()
.AddVideoConferencingApi()
.AddMailApi()
.AddAIApi()
.AddSearchApi()
.AddHelpDeskApi()
.Build();
// 方式三:模块枚举模式
builder.Services.AddFeishuServices(
FeishuModule.Organization,
FeishuModule.Message,
FeishuModule.ChatGroup,
FeishuModule.Spreadsheets,
FeishuModule.Bitable,
FeishuModule.Calendar,
FeishuModule.VideoConferencing,
FeishuModule.Mail,
FeishuModule.AI,
FeishuModule.Search,
FeishuModule.HelpDesk
);
var app = builder.Build();
app.Run();建造者方法清单
| 方法 | 模块 | 方法 | 模块 |
|---|---|---|---|
AddOrganizationApi() | 组织架构 | AddDocxApi() | 文档 |
AddMessageApi() | 消息服务 | AddSpreadsheetsApi() | 电子表格 |
AddChatGroupApi() | 群聊管理 | AddBiTableApi() | 多维表格 |
AddApprovalApi() | 审批流程 | AddCalendarApi() | 日历日程 |
AddTaskApi() | 任务管理 | AddVideoConferencingApi() | 视频会议 |
AddCardApi() | 卡片管理 | AddMailApi() | 邮箱管理 |
AddAttendanceApi() | 考勤管理 | AddAIApi() | AI 能力 |
AddDriveApi() | 云盘管理 | AddSearchApi() | 搜索 |
AddWikiApi() | 知识库 | AddHelpDeskApi() | 服务台 |
配置文件
{
"FeishuApps": [
{
"AppKey": "default",
"AppId": "your_feishu_app_id",
"AppSecret": "your_feishu_app_secret",
"BaseUrl": "https://open.feishu.cn",
"TimeOut": 30,
"RetryCount": 3,
"RetryDelayMs": 1000,
"EnableLogging": true,
"IsDefault": true
}
]
}使用 API 服务
using Mud.Feishu;
using Mud.Feishu.DataModels;
using Mud.Feishu.DataModels.Organization;
public class UserService
{
private readonly IFeishuTenantV3User _userApi;
public UserService(IFeishuTenantV3User userApi)
{
_userApi = userApi;
}
public async Task<FeishuApiResult<GetUserInfoResult>?> GetUserAsync(string userId)
{
return await _userApi.GetUserInfoByIdAsync(userId);
}
public async Task<FeishuApiResult<CreateOrUpdateUserResult>?> CreateUserAsync(CreateUserRequest request)
{
return await _userApi.CreateUserAsync(request);
}
}⚙️ 配置选项
FeishuAppConfig 配置项
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
AppKey | string | - | 应用唯一标识(必需) |
AppId | string | - | 飞书应用 ID(必需) |
AppSecret | string | - | 飞书应用密钥(必需) |
BaseUrl | string | https://open.feishu.cn | API 基础地址 |
AllowCustomBaseUrl | bool | false | 是否允许自定义基础 URL(存在 SSRF 风险,仅特殊场景启用) |
TimeOut | int | 30 | HTTP 请求超时时间(秒) |
RetryCount | int | 3 | 失败重试次数 |
RetryDelayMs | int | 1000 | 重试延迟时间(毫秒) |
CircuitBreakerEnabled | bool | true | 是否启用熔断策略 |
CircuitBreakerFailureThreshold | int | 20 | 熔断失败率阈值(百分比) |
CircuitBreakerSamplingDurationSeconds | int | 60 | 熔断采样窗口时间(秒) |
CircuitBreakerBreakDurationSeconds | int | 60 | 熔断持续时间(秒) |
CircuitBreakerMinimumThroughput | int | 10 | 熔断最小吞吐量 |
TokenRefreshThreshold | int | 300 | 令牌刷新阈值(秒) |
EnableLogging | bool | true | 是否启用日志记录 |
IsDefault | bool | false | 是否为默认应用 |
⚠️ 多应用模式下,弹性策略为全局共享,仅默认应用(
IsDefault=true)的配置生效。
配置验证
FeishuAppConfig 提供 Validate() 方法校验配置项有效性:
TimeOut必须在 1-300 秒之间RetryCount必须在 0-10 次之间RetryDelayMs必须在 100-60000 毫秒之间TokenRefreshThreshold必须在 60-3600 秒之间AppId必须以cli_或app_开头,且长度至少为 20 字符AppSecret长度至少为 16 字符BaseUrl必须是有效的 HTTP/HTTPS URL 格式
ℹ️ 自 3.0.0 起,为适配 AOT 源生成配置绑定,
FeishuAppConfig已移除required修饰,必填校验统一由Validate()承担(源生成绑定器通过new T()构造)。
安全建议
AppId和AppSecret是飞书应用的身份凭证,请妥善保管- 建议使用环境变量或安全的配置管理系统来存储敏感信息
- 非必要不要开启
AllowCustomBaseUrl(存在 SSRF 风险) - 生产环境必须启用签名验证和时间戳验证(详见 Webhook 文档)
📋 API 模块总览
| 模块分类 | API 版本 | 接口(典型) | 主要功能 |
|---|---|---|---|
| 组织管理 | V3 | IFeishuTenantV3User、IFeishuTenantV3Departments | 用户、部门、职级、职务、职务族、用户组、角色、单位、工作城市、人员类型 |
| 消息服务 | V1 | IFeishuTenantV1Message、IFeishuTenantV1BatchMessage | 消息发送/回复/编辑/转发、表情回复、Pin、加急、消息内资源、上传下载 |
| 群聊管理 | V1 | IFeishuTenantV1ChatGroup、IFeishuTenantV1ChatGroupMember | 群信息、群成员、群公告、群标签页、群菜单 |
| 审批流程 | V4 / V2 | IFeishuTenantV4Approval、IFeishuTenantV4ApprovalTask | 审批定义与实例、审批任务、评论、第三方审批、审批文件、查询、订阅 |
| 任务管理 | V2 | IFeishuTenantV2Task、IFeishuTenantV2TaskCustomFields | 任务、子任务、成员、清单、提醒、依赖、自定义字段、评论、附件、分组、活动订阅 |
| 卡片管理 | V1 | IFeishuTenantV1Card、IFeishuTenantV1CardElements | 卡片实体创建/更新/局部更新、卡片元素 |
| 考勤管理 | V1 | IFeishuTenantV1AttendanceUserFlows、IFeishuTenantV1AttendanceGroups | 打卡流水、考勤组、考勤统计、班次、考勤档案 |
| 云盘管理 | V1 | IFeishuTenantV1DriveFiles、IFeishuTenantV1DrivePermissions | 文件元数据/复制/移动/删除、快捷方式、上传下载(含分片)、导入导出、点赞、文件夹、版本、媒体、权限、事件订阅、评论 |
| 知识库 | V2 | IFeishuTenantV2Wiki、IFeishuTenantV2WikiNodes | 知识空间、空间成员、空间设置、知识节点 |
| 文档管理 | V1 | IFeishuTenantV1Docx、IFeishuTenantV1DocxBlocks | 文档创建获取、文档块读写、批量操作、内容转换 |
| 画板管理 | V1 | IFeishuTenantV1Board | 画板主题、缩略图、PlantUML/Mermaid 解析、节点创建与读取 |
| 电子表格 | V3 / V2 | IFeishuTenantV3Spreadsheets、IFeishuV3SpreadsheetRange | 表格、区域、数据、单元格、筛选、筛选视图、浮动图片、保护范围、数据验证、条件格式 |
| 多维表格 | V1 / V2 | IFeishuTenantV1Bitable、IFeishuTenantV2BitableRole | 应用、数据表、记录、字段、视图、表单、仪表盘、角色、自动化流程 |
| 日历日程 | V4 | IFeishuTenantV4Calendar、IFeishuTenantV4CalendarEvent | 日历、ACL、日程事件 |
| 视频会议 | V1 | IFeishuTenantV1VideoConferencingMeeting、IFeishuTenantV1VideoConferencingRoom | 会议、配置、会议室、层级、预定、录制、纪要、导出、数据、报表 |
| AI 能力 | V1 | IFeishuTenantV1AIDocument、IFeishuTenantV1AIOpticalCharRecognition | 文档解析、OCR、语音转文字、文本翻译 |
| 邮箱管理 | V1 | IFeishuTenantV1MailMessage、IFeishuTenantV1MailTemplate | 邮件消息、别名、联系人、草稿、文件夹、邮件组、标签、公共邮箱、规则、模板、会话 |
| 搜索 | V2 | IFeishuTenantV2SearchDataSource、IFeishuTenantV2SearchDocWiki | 数据源、文档/知识库搜索、套件搜索 |
| 服务台 | V1 | IFeishuTenantV1HelpDeskAgent、IFeishuTenantV1HelpDeskTicket | 客服管理、工单管理 |
令牌类型的接口划分
同一业务对象通常按令牌类型提供三套接口,继承关系为「父类公共接口 ← 租户令牌接口 / 用户令牌接口」:
| 接口类型 | 命名示例 | 说明 |
|---|---|---|
| 父类接口(公共) | IFeishuV3User | 租户与用户令牌均可调用的公共方法 |
| 租户令牌接口 | IFeishuTenantV3User | 使用 tenant_access_token 调用(创建、更新、删除等) |
| 用户令牌接口 | IFeishuUserV3User | 使用 user_access_token 调用(以当前用户身份查询等) |
组织管理示例
// 用户管理:父类接口 IFeishuV3User 提供查询类方法,租户接口补充写操作
public interface IFeishuV3User
{
Task<FeishuApiResult<GetUserInfoResult>?> GetUserInfoByIdAsync(string userId);
Task<FeishuApiResult<BatchGetUserResult>?> GetUserByIdsAsync(IEnumerable<string> userIds);
Task<FeishuApiResult<GetUserPageListResult>?> GetUserByDepartmentIdAsync(string departmentId);
}
public interface IFeishuTenantV3User : IFeishuV3User
{
Task<FeishuApiResult<CreateOrUpdateUserResult>?> CreateUserAsync(CreateUserRequest request);
Task<FeishuApiResult<DeleteUserResult>?> DeleteUserByIdAsync(string userId);
Task<FeishuApiResult<string>?> GetJsTicketAsync(...);
}
public interface IFeishuUserV3User : IFeishuV3User
{
Task<FeishuApiResult<GetUserInfoResult>?> GetUserInfoAsync();
}// 部门树
var result = await _deptApi.GetDepartmentsByParentIdAsync("0", fetch_child: true);
if (result?.Code == 0)
{
var departments = result.Data.Items;
var nextPageToken = result.Data.PageToken;
}消息服务示例
var textContent = new MessageTextContent { Text = "Hello World!" };
var result = await _messageApi.SendMessageAsync(new SendMessageRequest
{
ReceiveId = "user_123",
MsgType = "text",
Content = JsonSerializer.Serialize(textContent)
}, receive_id_type: "user_id");
if (result?.Code != 0)
{
throw new Exception($"发送失败: {result?.Msg}");
}分页处理
分页接口统一以 ...PageListAsync 命名,返回 FeishuApiPageListResult<T>,通过 PageToken 迭代:
public async Task<List<T>> GetAllItemsAsync<T>(
Func<string?, Task<FeishuApiPageListResult<T>>> pageFetcher)
{
var allItems = new List<T>();
string? pageToken = null;
do
{
var result = await pageFetcher(pageToken);
if (result.Code == 0 && result.Data?.Items != null)
{
allItems.AddRange(result.Data.Items);
pageToken = result.Data.PageToken;
}
else
{
break;
}
} while (!string.IsNullOrEmpty(pageToken));
return allItems;
}
// 使用示例
var allUsers = await GetAllItemsAsync(pageToken =>
userApi.GetUserByDepartmentIdAsync("dept_123", page_size: 50, page_token: pageToken));🏢 多应用支持
// 配置多个应用
builder.Services.AddFeishuApp(configure =>
{
configure.AddDefaultApp("default", "cli_xxx", "dsk_xxx");
configure.AddApp("hr-app", "cli_yyy", "dsk_yyy", opt =>
{
opt.TimeOut = 45;
opt.RetryCount = 5;
});
});public class MultiAppService
{
private readonly IFeishuAppManager _appManager;
public MultiAppService(IFeishuAppManager appManager)
{
_appManager = appManager;
}
// 方式一:获取指定应用的 API(内部已切换应用上下文,推荐)
public async Task UseSpecificAppAsync()
{
var userApi = _appManager.GetWebApi<IFeishuTenantV3User>("hr-app");
var result = await userApi.GetUserInfoByIdAsync("user_123");
}
// 方式二:使用 BeginScope 在作用域内切换应用上下文(作用域结束自动恢复)
public async Task UseScopedAppAsync(IFeishuTenantV3User userApi)
{
using (userApi.BeginScope("hr-app"))
{
// 在此作用域内,userApi 的所有调用都使用 hr-app 的凭证
var result = await userApi.GetUserInfoByIdAsync("user_123");
}
}
}| API | 说明 |
|---|---|
AddFeishuApp(IConfiguration) | 从配置注册(单/多应用) |
AddFeishuApp(Action<...> configure) | 代码方式注册多应用 |
configure.AddDefaultApp(appKey, appId, appSecret) | 添加默认应用 |
configure.AddApp(appKey, appId, appSecret, Action<options>) | 添加命名应用 + 选项覆盖 |
IFeishuAppManager.GetWebApi<T>(appKey) | 获取指定应用的 API 实例并切换上下文 |
IFeishuAppManager.GetDefaultWebApi<T>() | 获取默认应用的 API 实例 |
IFeishuAppManager.ConfiguredAppKeys | 获取全部已配置的 AppKey(不触发懒加载) |
api.BeginScope(appKey) | 在作用域内切换应用上下文 |
重要提示:
- ⚠️ 线程安全:
UseApp()/UseDefaultApp()为无作用域切换,会改变服务实例状态,长生命周期宿主存在上下文泄漏风险;推荐使用GetWebApi<T>(appKey)或BeginScope(appKey)。 - 📝 后台任务:必须明确指定应用,不能依赖默认应用。
- 🔄 凭据轮换:配置热更新检测到
AppId/AppSecret变更时,会立即清除该应用的全部持久化令牌;仅BaseUrl/TimeOut等变更时保留令牌热迁移。 - 🏢 多租户:多租户 = 多应用,但
UseApp/BeginScope只切换令牌与端点,不做租户隔离授权,需业务层自行实现。
💡 令牌管理、多应用/多租户与配置热更新的完整说明见飞书多应用管理及认证授权指南。
🎯 常见操作快速参考
令牌管理
// 直接从应用上下文获取指定类型的令牌管理器(令牌管理实现位于 Mud.HttpUtils)
var token = await appContext
.GetTokenManager(FeishuTokenTypes.TenantAccessToken)
.GetTokenAsync();
// 注意:自 3.0.0 起,GetAllApps() 只返回已实例化的应用,不会触发懒初始化
// 需要获取全部已配置的 AppKey 请使用 ConfiguredAppKeys
foreach (var appKey in _appManager.ConfiguredAppKeys)
{
Console.WriteLine(appKey);
}ℹ️ 令牌缓存条目按应用(AppKey)通过键前缀隔离,
TokenKeyBuilder是 Memory / Redis 令牌键布局的单一真相源。
自定义模块注册
通过 IFeishuModuleRegistrar 扩展自定义 API 模块:
public class CustomModuleRegistrar : IFeishuModuleRegistrar
{
public FeishuModule Module => FeishuModule.All + 1;
public void Register(IServiceCollection services)
{
services.AddTransient<ICustomApi, CustomApi>();
}
}
// 注册自定义模块
builder.Services.CreateFeishuServicesBuilder()
.RegisterModule(new CustomModuleRegistrar())
.Build();错误处理
public class FeishuServiceBase
{
protected async Task<T> ExecuteWithErrorHandling<T>(
Func<Task<FeishuApiResult<T>>> operation,
string operationName)
{
var result = await operation();
if (result.Code != 0)
{
throw new FeishuServiceException(
$"飞书 API 调用失败: {operationName}",
result.Code,
result.Msg);
}
return result.Data!;
}
}
// 使用示例
public async Task<UserInfo> GetUserSafelyAsync(string userId)
{
return await ExecuteWithErrorHandling(
() => userApi.GetUserInfoByIdAsync(userId),
"获取用户信息");
}💡 所有 API 统一返回
FeishuApiResult<T>(含Code/Msg/Data),业务判断以Code == 0为准; 文件下载类接口(返回Task<byte[]?>)存在「HTTP 200 + JSON 错误体」的残余风险,需按接口文档声明处理。
⚡ Native AOT 支持
自 3.0.0 起,Mud.Feishu 在 net8.0+ 目标框架下一等公民支持 .NET Native AOT 发布:
- 全链路源生成 JSON 序列化(内置
FeishuJsonContext) - 源生成配置绑定(
EnableConfigurationBindingGenerator) - AOT 安全辅助类
FeishuJsonAot - 通过 AOT 严格模式质量门禁保证
AOT00x/IL2026/IL3050诊断为 0
dotnet publish -r win-x64 -c Release /p:PublishAot=true⚠️ 注意事项:
- 自定义类型的序列化请通过
FeishuJsonDefaults.ConfigureUserResolver注册自定义JsonSerializerContext- 扩展配置 DTO 请勿使用
required修饰,改在Validate()方法中校验
📊 与原生飞书 SDK 的对比
| 对比维度 | 原生 SDK 调用 | Mud.Feishu 组件 | 优势说明 |
|---|---|---|---|
| 开发效率 | 需要手动构造 HTTP 请求、处理响应、解析 JSON 等大量样板代码 | 只需调用简洁的接口方法,一行代码完成操作 | 大幅减少代码量,提高开发效率 |
| 类型安全 | 手动处理 JSON 序列化/反序列化,容易出现类型转换错误 | 提供完整的强类型支持,编译时就能发现类型错误 | 提高代码健壮性,减少运行时错误 |
| 令牌管理 | 需要手动获取、刷新和管理访问令牌 | 自动处理令牌获取和刷新机制 | 减少开发者负担,避免令牌管理错误 |
| 异常处理 | 需要手动处理各种网络异常和业务异常 | 统一的响应模型与异常处理机制 | 简化异常处理逻辑,提高代码可读性 |
| 重试/熔断 | 需要手动实现重试逻辑 | 内置智能重试与熔断机制(可配置) | 提高系统稳定性 |
| 可测试性 | 直接调用 HTTP 接口,难以进行单元测试 | 基于接口设计,易于进行 Mock 测试 | 提高代码质量和可维护性 |
| 文档完善度 | 需要在飞书官方文档中查找各个接口的详细说明 | 提供完整的中文 API 文档和示例代码 | 降低学习成本,快速上手 |
| AOT 部署 | 反射式序列化难以 AOT | 全链路源生成,可直接发布原生二进制 | 启动更快、内存更省 |
🛠️ 技术栈
设计模式
- 策略模式 - 事件处理器接口和实现
- 工厂模式 - 处理器工厂和模块注册工厂
- 建造者模式 - 服务注册构造者
- 中间件模式 - Webhook 中间件和限流中间件
企业级特性
- 自动令牌管理 - 智能缓存(提前刷新),解决缓存击穿和竞态条件
- 智能重试 - 基于 Polly 策略,指数退避算法
- 统一异常处理 - 统一响应模型与详细日志记录
- 高性能缓存 -
ConcurrentDictionary+Lazy<Task>,并发安全 - 分布式支持 - 配合
Mud.Feishu.Redis实现多实例部署
依赖项
| 包 | 版本 | 说明 |
|---|---|---|
| Mud.HttpUtils | v2.0.7 | HTTP 客户端工具类(含源代码生成器) |
| Mud.HttpUtils.Generator | v2.0.7 | HTTP 客户端代码生成器(编译时) |
| Mud.Feishu.Abstractions | 同版本 | 飞书 SDK 抽象层 |
| Mud.Feishu.DataModels | 同版本 | 飞书 API 强类型数据模型 |
框架支持
| .NET 版本 | 支持状态 | 说明 |
|---|---|---|
| .NET Standard 2.0 | ✅ | 兼容 .NET Framework 4.6.1+ |
| .NET 6.0 | ✅ LTS | 长期支持版本 |
| .NET 8.0 | ✅ LTS | 长期支持版本(推荐,支持 Native AOT 发布) |
| .NET 10.0 | ✅ LTS | 长期支持版本(推荐,支持 Native AOT 发布) |
🔗 相关项目
- Mud.Feishu.Abstractions - 令牌管理、多应用与事件处理抽象层
- Mud.Feishu.DataModels - HTTP API 强类型数据模型
- Mud.Feishu.Authentication - 用户认证中间件
- Mud.Feishu.EventCallback - 事件回调强类型数据模型
- Mud.Feishu.WebSocket - WebSocket 实时事件订阅
- Mud.Feishu.Webhook - Webhook HTTP 回调事件处理
- Mud.Feishu.Redis - Redis 分布式去重扩展
📄 许可证
MudFeishu 遵循 MIT 许可证。
如果觉得 MudFeishu 对你有帮助,请给个 ⭐Star 支持一下!
Made with ❤️ by MudTools