企业项目中经常需要批量操作飞书群组:项目启动时自动建群拉人、系统告警自动推送、员工入职离职自动处理群权限等。手动操作效率低且容易出错。
本文基于 Mud.Feishu ,从实际代码出发,讲解:
- Tenant Access Token 获取机制
- 聊天群组管理
- 成员批量管理
- 自动推送消息
- 错误处理和重试策略
为什么需要服务端集成飞书?
典型的业务场景
在企业日常业务开展过程中,经常会遇到以下场景:
| 应用场景 | 核心功能 | 关键技术点 | 业务价值 |
|---|---|---|---|
| 项目群组自动化创建 | - 新项目启动时自动创建项目群组 - 根据项目类型和人员角色批量拉入相关成员 - 设置群组名称、描述、权限等规范配置 |
- 群组创建API - 批量成员添加 - 权限模板配置 |
提高项目启动效率,确保团队沟通规范性 |
| 系统告警/通知自动推送 | - 监控系统告警信息自动发送到指定飞书群 - 业务流程状态变更通知 - 定期报告和数据统计自动推送 |
- 富文本消息发送 - 定时任务调度 - 消息模板管理 |
及时通知相关人员,提升响应速度和决策效率 |
| 组织架构同步与批量管理 | - HR系统组织架构变更同步到飞书 - 批量创建部门群组并同步成员 - 员工入职/离职时自动处理群组权限 |
- 组织架构API集成 - 批量群组管理 - 权限自动分配 |
保持组织架构一致性,减少人工维护成本 |
核心价值:服务端集成带来的优势
| 价值维度 | 核心特性 | 具体表现 | 技术优势 |
|---|---|---|---|
| 🚀 自动化 | 减少人工操作,提高工作效率 | - 群组创建、成员管理、消息推送全流程自动化 - 7x24 小时无人值守运行 - 业务规则驱动的智能处理 |
程序化执行,减少人为错误,提升处理速度和一致性 |
| 🔧 业务解耦 | 独立于飞书客户端,可集成到现有系统 | - 不依赖人工操作飞书客户端 - 与 ERP、HR、OA 等业务系统无缝集成 - API 接口标准化,易于扩展和维护 |
系统集成灵活,可嵌入现有工作流,降低耦合度 |
| 🛡️ 安全可靠 | 服务端级别的高可用性保障 | - 企业级应用的认证和授权机制 - 操作日志完整记录,便于审计追踪 - 异常处理和重试机制,确保消息送达 |
企业级安全标准,操作可追溯,系统稳定性高 |
本文目标
实际解决企业中的几个问题:
- ✅ Token 管理:获取、缓存、自动刷新机制
- ✅ 群组操作:创建、查询、更新、解散
- ✅ 成员管理:批量添加、移除、权限控制
- ✅ 消息推送:文本、富文本、卡片等格式
- ✅ 异常处理:错误码解析、重试策略、日志记录
准备工作:进入飞书开放平台
1. 创建应用
首先访问 飞书开放平台 并创建企业自建应用:
-
登录飞书开放平台
- 使用企业管理员账号登录
- 进入"开发者后台" -> "创建应用"
-
选择应用类型
- 选择"企业自建应用"
- 填写应用名称,如"企业群管系统"
- 选择应用图标和描述
-
获取关键信息
- App ID:应用唯一标识符
- App Secret:应用密钥,用于获取访问令牌
⚠️ 注意:App Secret 泄露会导致安全风险,生产环境中必须使用密钥管理服务。
2. 配置权限
在应用详情页中,找到"权限管理"并添加以下必要权限:
核心群组权限
contact:group:readonly # 获取群组信息 contact:group:update # 更新群组信息 contact:group:delete # 解散群组
群组成员权限
contact:group.member:readonly # 获取群组成员信息 contact:group.member:add # 添加群组成员 contact:group.member:delete # 移除群组成员
消息发送权限
im:message # 发送消息(用于消息推送示例) im:chat:announcement # 群公告操作(可选)
高级权限(根据需要添加)
contact:user.base:readonly # 读取用户基本信息 contact:department:readonly # 读取部门信息
3. 发布与启用
-
应用发布
- 确保应用状态为"已发布"
- 配置应用图标、名称等基本信息
-
授权范围
- 将应用授权给测试范围(如自己所在部门)
- 生产环境需要管理员审批后才能全公司使用
-
获取服务器地址
- 记录应用的服务器地址:国内版
https://open.feishu.cn
- 记录应用的服务器地址:国内版
核心概念与流程解析
1. 飞书服务端 API 认证机制:Tenant Access Token
什么是 Tenant Access Token?
Tenant Access Token(租户访问令牌)是飞书开放平台的 API 调用凭证,具有以下特点:
- 租户级别:代表整个企业应用的访问权限
- 服务端调用:适用于服务器端的自动化场景
- 高权限:可获得企业内所有受权数据
- 自动刷新:支持通过 App ID 和 App Secret 重新获取
获取流程详解
技术实现要点:
- 使用
App ID + App Secret调用认证接口 - 获取
tenant_access_token和过期时间 - 实现内存缓存,避免频繁请求认证接口
- Token 过期前自动刷新机制
2. 使用 Mud.Feishu 调用通用步骤
步骤概览
- 获取 Token:调用认证接口获取有效的访问令牌
- 构造请求:设置 HTTP 方法、URL、请求头等
- 携带认证:在请求头中添加 Bearer Token
- 处理请求体:构造 JSON 格式的请求参数
- 解析响应:处理 API 返回的 JSON 响应数据
简化的调用流程
// 传统方式 - 需要大量样板代码 var httpClient = new HttpClient(); var token = await GetTokenAsync(); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); var json = JsonSerializer.Serialize(request); var response = await httpClient.PostAsync(url, new StringContent(json, Encoding.UTF8, "application/json")); var result = JsonSerializer.Deserialize<ResponseModel>(await response.Content.ReadAsStringAsync()); // Mud.Feishu 方式 - 简洁直观 var result = await _chatGroupApi.CreateChatGroupAsync(request); // 所有认证、序列化、异常处理都已内置处理
使用 Mud.Feishu 进行 .NET 自动化群组管理与消息推送实战
1. 环境与项目搭建
创建新项目
# 创建 .NET 8 Web API 项目 dotnet new webapi -n FeishuGroupManager # 切换到项目目录 cd FeishuGroupManager # 安装必要 NuGet 包 dotnet add package Mud.Feishu --version 1.0.3 dotnet add package Microsoft.Extensions.Http dotnet add package System.Text.Json
所有组件都使用微软官方库中的标准组件,不添加多余的第三方库。
配置文件设置
创建 appsettings.json:
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "Feishu": { "AppId": "cli_xxxxxxxxxxxxxxxx", "AppSecret": "your_secret_key_here", "BaseUrl": "https://open.feishu.cn" } }
服务注册配置
在 Program.cs 中注册飞书服务:
using Mud.Feishu; var builder = WebApplication.CreateBuilder(args); // 注册飞书 API 服务 builder.Services.AddFeishuApiService(builder.Configuration); var app = builder.Build(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
2. 核心服务类设计:FeishuChatGroupService
创建核心服务类来封装飞书 API 调用:
using Mud.Feishu; using Mud.Feishu.Exceptions; using Mud.Feishu.ChatGroup; using Microsoft.Extensions.Logging; /// <summary> /// 飞书群组管理服务 /// </summary> public class FeishuChatGroupService { private readonly IFeishuTenantV1ChatGroup _chatGroupApi; private readonly IFeishuTenantV1ChatGroupMember _memberApi; private readonly IFeishuTenantV1Message _messageApi; private readonly ILogger<FeishuChatGroupService> _logger; public FeishuChatGroupService( IFeishuTenantV1ChatGroup chatGroupApi, IFeishuTenantV1ChatGroupMember memberApi, IFeishuTenantV1Message messageApi, ILogger<FeishuChatGroupService> logger) { _chatGroupApi = chatGroupApi; _memberApi = memberApi; _messageApi = messageApi; _logger = logger; } }
3. 第一步:获取 Tenant Access Token
MudFeishu 内置了自动令牌管理,但我们可以展示手动获取的过程:
/// <summary> /// 获取飞书租户访问令牌(手动实现示例) /// </summary> public async Task<string> GetTenantAccessTokenAsync() { try { // Mud.Feishu 会自动处理 Token 获取和刷新 // 这里仅展示原理,实际使用时直接调用 API 即可 _logger.LogInformation("正在获取飞书访问令牌..."); // 实际使用中,Token 会自动管理,无需手动获取 return "Mud.Feishu自动管理的Token"; } catch (Exception ex) { _logger.LogError(ex, "获取飞书访问令牌失败"); throw new FeishuException("Token获取失败", -1, ex.Message); } }
🔧 技术要点:Mud.Feishu 内置 Token 管理,包括获取、缓存、刷新逻辑。
4. 第二步:实现群组操作
a. 创建群聊
此方法实现了飞书群组的完整创建流程,主要操作包括:
- 构造群组创建请求,设置群组基本信息(名称、描述)
- 配置群组类型和权限(私有群组、免审批加入)
- 添加初始成员列表,支持批量邀请
- 调用飞书API执行群组创建
- 处理创建结果,包含错误检查和异常处理
- 返回创建成功的群组ID,供后续操作使用
/// <summary> /// 创建新的飞书群组 /// </summary> /// <param name="groupName">群组名称</param> /// <param name="description">群组描述</param> /// <param name="memberIds">初始成员ID列表</param> /// <returns>创建结果,包含群组ID</returns> public async Task<string> CreateChatAsync(string groupName, string description, string[] memberIds) { try { _logger.LogInformation("开始创建群组: {GroupName}", groupName); var request = new CreateChatRequest { Name = groupName, Description = description, UserIdList = memberIds, GroupMessageType = "chat", // 对话消息 ChatMode = "group", // 群组模式 ChatType = "private", // 私有群组 JoinMessageVisibility = "all_members", // 入群消息所有人可见 LeaveMessageVisibility = "all_members", // 退群消息所有人可见 MembershipApproval = "no_approval_required", // 无需审批加入 EditPermission = "all_members", // 所有人可编辑 AddMemberPermission = "all_members", // 所有人可添加成员 ShareCardPermission = "all_members" // 所有人可分享名片 }; var result = await _chatGroupApi.CreateChatGroupAsync(request); if (result == null || result.Code != 0) { _logger.LogError("创建群组失败: {Error}", result?.Msg ?? "未知错误"); throw new FeishuException("创建群组失败", result?.Code ?? -1, result?.Msg ?? "未知错误"); } var chatId = result.Data!.ChatId; _logger.LogInformation("群组创建成功: {ChatId}", chatId); return chatId; } catch (FeishuException) { throw; // 重新抛出飞书异常 } catch (Exception ex) { _logger.LogError(ex, "创建群组时发生系统异常"); throw new FeishuException("系统异常", -999, ex.Message); } }
b. 获取群组列表
此方法实现了飞书群组列表的分页获取功能,主要操作包括:
- 构造分页查询请求,支持自定义页大小和分页令牌
- 调用飞书API获取指定页面的群组列表数据
- 处理API响应,包含错误检查和异常处理
- 记录获取到的群组数量,便于监控和调试
- 返回包含群组列表和分页信息的完整结果
- 支持继续分页查询,可用于群组数据的批量处理
/// <summary> /// 获取群组列表 /// </summary> /// <param name="pageSize">页大小</param> /// <param name="pageToken">分页令牌</param> /// <returns>群组分页列表结果</returns> public async Task<FeishuApiPageListResult<ChatItemInfo>> GetChatListAsync(int pageSize = 50, string? pageToken = null) { try { _logger.LogInformation("获取群组列表,页大小: {PageSize}", pageSize); var result = await _chatGroupApi.GetChatGroupPageListAsync( page_size: pageSize, page_token: pageToken); if (result == null || result.Code != 0) { _logger.LogError("获取群组列表失败: {Error}", result?.Msg ?? "未知错误"); throw new FeishuException("获取群组列表失败", result?.Code ?? -1, result?.Msg ?? "未知错误"); } _logger.LogInformation("获取到 {Count} 个群组", result.Data?.Items?.Count ?? 0); return result.Data!; } catch (FeishuException) { throw; } catch (Exception ex) { _logger.LogError(ex, "获取群组列表时发生系统异常"); throw new FeishuException("系统异常", -999, ex.Message); } }
c. 获取群组详情
此方法实现了获取指定群组的详细信息功能,主要操作包括:
- 根据群组ID调用飞书API获取群组完整信息
- 获取群组的所有配置属性(名称、描述、权限设置等)
- 处理API响应,包含错误检查和异常处理
- 记录操作成功日志,便于追踪群组访问情况
- 返回完整的群组详情对象,包含所有群组属性
- 支持异常传播,确保调用方能正确处理错误情况
/// <summary> /// 获取群组详细信息 /// </summary> /// <param name="chatId">群组ID</param> /// <returns>群组详细信息</returns> public async Task<GetChatGroupInfoResult> GetChatDetailAsync(string chatId) { try { _logger.LogInformation("获取群组详情: {ChatId}", chatId); var result = await _chatGroupApi.GetChatGroupInoByIdAsync(chatId); if (result == null || result.Code != 0) { _logger.LogError("获取群组详情失败: {Error}", result?.Msg ?? "未知错误"); throw new FeishuException("获取群组详情失败", result?.Code ?? -1, result?.Msg ?? "未知错误"); } _logger.LogInformation("获取群组详情成功: {GroupName}", result.Data?.Name); return result.Data!; } catch (FeishuException) { throw; } catch (Exception ex) { _logger.LogError(ex, "获取群组详情时发生系统异常"); throw new FeishuException("系统异常", -999, ex.Message); } }
d. 更新群组信息
此方法实现了群组信息的动态更新功能,主要操作包括:
- 构造群组更新请求,支持修改群组名称和描述
- 设置群组模式和相关权限,保持群组类型一致性
- 调用飞书API执行群组信息更新操作
- 处理更新结果,包含错误检查和异常处理
- 记录更新操作日志,便于审计和追踪
- 返回布尔值指示更新操作是否成功完成
/// <summary> /// 更新群组信息 /// </summary> /// <param name="chatId">群组ID</param> /// <param name="newName">新的群组名称</param> /// <param name="newDescription">新的群组描述</param> /// <returns>更新结果</returns> public async Task<bool> UpdateChatAsync(string chatId, string newName, string newDescription) { try { _logger.LogInformation("更新群组信息: {ChatId} -> {NewName}", chatId, newName); var request = new UpdateChatRequest { Name = newName, Description = newDescription, // 保持其他设置不变 ChatMode = "group", EditPermission = "all_members" }; var result = await _chatGroupApi.UpdateChatGroupByIdAsync(chatId, request); if (result == null || result.Code != 0) { _logger.LogError("更新群组失败: {Error}", result?.Msg ?? "未知错误"); throw new FeishuException("更新群组失败", result?.Code ?? -1, result?.Msg ?? "未知错误"); } _logger.LogInformation("群组更新成功: {ChatId}", chatId); return true; } catch (FeishuException) { throw; } catch (Exception ex) { _logger.LogError(ex, "更新群组时发生系统异常"); throw new FeishuException("系统异常", -999, ex.Message); } }
e. 添加群组成员
此方法实现了批量添加成员到群组的功能,主要操作包括:
- 构造批量添加成员请求,支持一次添加多个用户
- 验证成员ID列表的有效性和数量统计
- 调用飞书API执行批量成员添加操作
- 处理添加结果,区分成功添加和失败的成员
- 记录详细的操作日志,包含成功和失败的统计信息
- 返回包含无效ID列表的详细结果,便于后续处理
/// <summary> /// 添加成员到群组 /// </summary> /// <param name="chatId">群组ID</param> /// <param name="memberIds">要添加的成员ID列表</param> /// <returns>添加结果</returns> public async Task<AddMemberResult> AddChatMembersAsync(string chatId, string[] memberIds) { try { _logger.LogInformation("向群组添加成员: {ChatId}, 成员数: {Count}", chatId, memberIds.Length); var request = new MembersRequest { MemberIdList = memberIds }; var result = await _memberApi.AddMemberAsync(request); if (result == null || result.Code != 0) { _logger.LogError("添加群成员失败: {Error}", result?.Msg ?? "未知错误"); throw new FeishuException("添加群成员失败", result?.Code ?? -1, result?.Msg ?? "未知错误"); } _logger.LogInformation("成功添加 {SuccessCount} 个成员,失败 {FailedCount} 个", memberIds.Length - (result.Data?.InvalidIdList?.Count ?? 0), result.Data?.InvalidIdList?.Count ?? 0); return result.Data!; } catch (FeishuException) { throw; } catch (Exception ex) { _logger.LogError(ex, "添加群成员时发生系统异常"); throw new FeishuException("系统异常", -999, ex.Message); } }
f. 解散群组
此方法实现了永久解散群组的功能,主要操作包括:
- 根据群组ID调用飞书API执行群组解散操作
- 注意:此操作不可逆,解散后群组将永久删除
- 处理解散结果,包含错误检查和异常处理
- 记录关键操作日志,便于审计和追踪解散行为
- 返回布尔值指示解散操作是否成功完成
- 确保只有有权限的用户才能执行此敏感操作
/// <summary> /// 解散群组 /// </summary> /// <param name="chatId">要解散的群组ID</param> /// <returns>操作结果</returns> public async Task<bool> DeleteChatAsync(string chatId) { try { _logger.LogInformation("解散群组: {ChatId}", chatId); var result = await _chatGroupApi.DeleteChatGroupAsync(chatId); if (result == null || result.Code != 0) { _logger.LogError("解散群组失败: {Error}", result?.Msg ?? "未知错误"); throw new FeishuException("解散群组失败", result?.Code ?? -1, result?.Msg ?? "未知错误"); } _logger.LogInformation("群组解散成功: {ChatId}", chatId); return true; } catch (FeishuException) { throw; } catch (Exception ex) { _logger.LogError(ex, "解散群组时发生系统异常"); throw new FeishuException("系统异常", -999, ex.Message); } }
5. 第三步:在群内发送消息
本部分实现了群组内消息发送的核心功能,包括:
- 文本消息发送:支持纯文本内容的群组消息推送
- 富文本消息发送:支持格式化的富文本内容展示
- 消息构造与发送:统一的消息请求构造和API调用流程
- 发送结果处理:完整的错误检查和异常处理机制
- 消息ID追踪:返回消息唯一标识符,便于后续操作
- 日志记录:详细的发送操作日志,便于监控和调试
/// <summary> /// 在群组中发送文本消息 /// </summary> /// <param name="chatId">群组ID</param> /// <param name="content">消息内容</param> /// <returns>消息发送结果</returns> public async Task<string> SendTextMessageAsync(string chatId, string content) { try { _logger.LogInformation("发送消息到群组: {ChatId}, 内容长度: {Length}", chatId, content.Length); var request = new SendMessageRequest { ReceiveId = chatId, MsgType = "text", Content = new { text = content } }; var result = await _messageApi.SendMessageAsync(request); if (result == null || result.Code != 0) { _logger.LogError("发送消息失败: {Error}", result?.Msg ?? "未知错误"); throw new FeishuException("发送消息失败", result?.Code ?? -1, result?.Msg ?? "未知错误"); } var messageId = result.Data!.MessageId; _logger.LogInformation("消息发送成功: {MessageId}", messageId); return messageId; } catch (FeishuException) { throw; } catch (Exception ex) { _logger.LogError(ex, "发送消息时发生系统异常"); throw new FeishuException("系统异常", -999, ex.Message); } } /// <summary> /// 在群组中发送富文本消息 /// /// 富文本消息特点:支持格式化内容展示,包含标题、段落、换行等排版元素, /// 适用于通知公告、报告总结等需要结构化展示的场景 /// </summary> /// <param name="chatId">群组ID</param> /// <param name="title">消息标题</param> /// <param name="content">富文本内容</param> /// <returns>消息发送结果</returns> public async Task<string> SendRichMessageAsync(string chatId, string title, string content) { try { _logger.LogInformation("发送富文本消息到群组: {ChatId}", chatId); var richTextContent = new List<RichTextElement> { new RichTextElement { Tag = "text", Text = $"📢 {title}nn{content}" } }; var request = new SendMessageRequest { ReceiveId = chatId, MsgType = "post", Content = new { post = richTextContent } }; var result = await _messageApi.SendMessageAsync(request); if (result == null || result.Code != 0) { _logger.LogError("发送富文本消息失败: {Error}", result?.Msg ?? "未知错误"); throw new FeishuException("发送富文本消息失败", result?.Code ?? -1, result?.Msg ?? "未知错误"); } var messageId = result.Data!.MessageId; _logger.LogInformation("富文本消息发送成功: {MessageId}", messageId); return messageId; } catch (FeishuException) { throw; } catch (Exception ex) { _logger.LogError(ex, "发送富文本消息时发生系统异常"); throw new FeishuException("系统异常", -999, ex.Message); } }
完整代码示例与演示
控制器实现
创建 FeishuGroupController.cs 来演示完整业务流程:
using Microsoft.AspNetCore.Mvc; using Mud.Feishu; /// <summary> /// 飞书群组管理控制器 /// </summary> [ApiController] [Route("api/[controller]")] public class FeishuGroupController : ControllerBase { private readonly FeishuChatGroupService _chatGroupService; private readonly ILogger<FeishuGroupController> _logger; public FeishuGroupController( FeishuChatGroupService chatGroupService, ILogger<FeishuGroupController> logger) { _chatGroupService = chatGroupService; _logger = logger; } /// <summary> /// 创建项目群组并添加成员,然后发送欢迎消息 /// </summary> [HttpPost("create-project-group")] public async Task<IActionResult> CreateProjectGroup([FromBody] CreateProjectGroupRequest request) { try { _logger.LogInformation("开始创建项目群组: {ProjectName}", request.ProjectName); // 第一步:创建群组 var chatId = await _chatGroupService.CreateChatAsync( $"{request.ProjectName}项目群", $"这是 {request.ProjectName} 项目的专用沟通群组,用于项目进展同步和团队协作。", request.MemberIds ); // 第二步:等待片刻确保群组创建完成 await Task.Delay(2000); // 第三步:发送欢迎消息 var welcomeMessage = $@"✅ 项目群组创建完成 📋 项目信息 • 项目名称:{request.ProjectName} • 项目负责人:{request.ProjectManager} • 创建时间:{DateTime.Now:yyyy-MM-dd HH:mm:ss} 👥 群组成员 • 初始成员:{request.MemberIds.Length} 人 • 群组ID:{chatId} 📋 群组用途 技术团队在此群组处理: • 项目进度同步 • 技术问题讨论 • 资源协调 • 资料分享 祝项目顺利推进!🚀"; var messageId = await _chatGroupService.SendRichMessageAsync( chatId, "项目群组创建成功", welcomeMessage ); return Ok(new { success = true, data = new { chatId = chatId, messageId = messageId, projectName = request.ProjectName, memberCount = request.MemberIds.Length } }); } catch (FeishuException ex) { _logger.LogError(ex, "创建项目群组失败: {ErrorCode} - {Message}", ex.ErrorCode, ex.Message); return BadRequest(new { success = false, error = ex.Message, errorCode = ex.ErrorCode }); } catch (Exception ex) { _logger.LogError(ex, "创建项目群组时发生系统异常"); return StatusCode(500, new { success = false, error = "系统内部错误" }); } } /// <summary> /// 获取群组列表 /// </summary> [HttpGet("groups")] public async Task<IActionResult> GetGroups([FromQuery] int pageSize = 20, [FromQuery] string? pageToken = null) { try { var result = await _chatGroupService.GetChatListAsync(pageSize, pageToken); return Ok(new { success = true, data = new { items = result.Items, pageToken = result.PageToken, hasMore = !string.IsNullOrEmpty(result.PageToken) } }); } catch (Exception ex) { _logger.LogError(ex, "获取群组列表失败"); return StatusCode(500, new { success = false, error = "获取群组列表失败" }); } } /// <summary> /// 向指定群组发送系统通知 /// </summary> [HttpPost("send-notification")] public async Task<IActionResult> SendNotification([FromBody] SendNotificationRequest request) { try { var message = $@"📢 系统通知 {request.Title} {request.Content} --- 发送时间:{DateTime.Now:yyyy-MM-dd HH:mm:ss} 发送者:系统管理员"; var messageId = await _chatGroupService.SendRichMessageAsync( request.ChatId, "系统通知", message ); return Ok(new { success = true, messageId = messageId, timestamp = DateTime.Now }); } catch (Exception ex) { _logger.LogError(ex, "发送系统通知失败"); return StatusCode(500, new { success = false, error = "发送通知失败" }); } } } /// <summary> /// 创建项目群组请求模型 /// </summary> public class CreateProjectGroupRequest { public string ProjectName { get; set; } = string.Empty; public string ProjectManager { get; set; } = string.Empty; public string[] MemberIds { get; set; } = Array.Empty<string>(); } /// <summary> /// 发送通知请求模型 /// </summary> public class SendNotificationRequest { public string ChatId { get; set; } = string.Empty; public string Title { get; set; } = string.Empty; public string Content { get; set; } = string.Empty; }
完整业务流程演示
/// <summary> /// 程序入口 - 演示完整的群组管理流程 /// </summary> public class Program { public static async Task Main(string[] args) { // 创建服务容器 var services = new ServiceCollection(); // 配置日志 services.AddLogging(builder => { builder.AddConsole(); builder.SetMinimumLevel(LogLevel.Information); }); // 配置内存中的配置 var configuration = new ConfigurationBuilder() .AddInMemoryCollection(new[] { new KeyValuePair<string, string>("Feishu:AppId", "your_app_id"), new KeyValuePair<string, string>("Feishu:AppSecret", "your_app_secret"), new KeyValuePair<string, string>("Feishu:BaseUrl", "https://open.feishu.cn") }) .Build(); // 注册飞书服务 services.AddFeishuApiService(configuration); // 添加我们的群组管理服务 services.AddSingleton<FeishuChatGroupService>(); var serviceProvider = services.BuildServiceProvider(); var chatGroupService = serviceProvider.GetRequiredService<FeishuChatGroupService>(); try { Console.WriteLine("=== 飞书群组自动化管理演示 ===n"); // 示例1:创建技术交流群 Console.WriteLine("🎯 步骤1:创建 .NET 技术交流群"); var techMemberIds = new[] { "user_001", "user_002", "user_003" }; var techChatId = await chatGroupService.CreateChatAsync( ".NET技术交流群", "本群用于.NET技术交流、问题讨论和经验分享。", techMemberIds ); Console.WriteLine($"✅ 群组创建成功,ID: {techChatId}"); // 等待群组创建完成 await Task.Delay(3000); // 发送欢迎消息 Console.WriteLine("📝 步骤2:发送欢迎消息"); var welcomeMessage = @"📋 已加入 .NET 技术交流群 👥 群组目标 • 分享 .NET 开发经验和最佳实践 • 讨论技术难题和解决方案 • 交流最新技术趋势和发展 • 互相学习,共同进步 📋 群规说明 • 保持友善交流氛围 • 分享有价值的内容 • 尊重他人观点 • 禁止无关广告和链接 💻 技术交流促进代码进步。"; var messageId = await chatGroupService.SendRichMessageAsync( techChatId, "欢迎加入技术交流群", welcomeMessage ); Console.WriteLine($"✅ 欢迎消息发送成功,消息ID: {messageId}"); // 示例2:获取群组列表 Console.WriteLine("n📋 步骤3:获取群组列表"); var groupList = await chatGroupService.GetChatListAsync(20); Console.WriteLine($"✅ 获取到 {groupList.Items?.Count ?? 0} 个群组"); // 显示群组信息 if (groupList.Items != null) { foreach (var group in groupList.Items.Take(5)) { Console.WriteLine($" 📁 {group.Name} (ID: {group.ChatId})"); } } // 示例3:添加新成员 Console.WriteLine("n👥 步骤4:添加新成员到技术群"); var newMembers = new[] { "user_004", "user_005" }; var addResult = await chatGroupService.AddChatMembersAsync(techChatId, newMembers); Console.WriteLine($"✅ 成功添加 {newMembers.Length - (addResult.InvalidIdList?.Count ?? 0)} 个成员"); if (addResult.InvalidIdList != null && addResult.InvalidIdList.Count > 0) { Console.WriteLine($"⚠️ {addResult.InvalidIdList.Count} 个成员添加失败"); } // 发送新成员欢迎消息 await Task.Delay(2000); var newMemberMessage = @"👋 新成员加入 欢迎新朋友加入技术交流群! 🆕 新成员 • user_004 - 后端开发工程师 • user_005 - 前端开发工程师 📋 群规说明: • 技术问题优先解决 • 代码质量严格把控 • 定期技术分享 💻 提升代码水平。"; await chatGroupService.SendRichMessageAsync( techChatId, "新成员加入", newMemberMessage ); Console.WriteLine("✅ 新成员欢迎消息发送成功"); Console.WriteLine("n✅ 演示完成,所有API调用正常返回。"); } catch (FeishuException ex) { Console.WriteLine($"❌ 飞书API错误: {ex.Message} (错误码: {ex.ErrorCode})"); } catch (Exception ex) { Console.WriteLine($"❌ 系统错误: {ex.Message}"); } Console.WriteLine("n按任意键退出..."); Console.ReadKey(); } }
总结
回顾整个流程
通过本文完成了从创建应用到实现完整群组管理系统的全过程:
创建飞书应用 → 配置API权限 → 获取访问令牌 → 调用群组API → 实现业务逻辑 → 发送消息通知
一些建议
1. 错误处理与异常管理
🔧 FeishuException 处理策略
try { var result = await _chatGroupApi.CreateChatGroupAsync(request); // 处理成功结果 } catch (FeishuException ex) { // 飞书API业务异常 _logger.LogError(ex, "飞书API调用失败,错误码: {ErrorCode}", ex.ErrorCode); // 根据错误码进行不同处理 switch (ex.ErrorCode) { case 99991663: // 无权限 throw new BusinessException("用户无权限执行此操作"); case 99991401: // 群不存在 throw new BusinessException("指定的群组不存在"); default: throw; // 重新抛出未知异常 } } catch (Exception ex) { // 系统异常 _logger.LogCritical(ex, "系统发生未知异常"); throw new SystemException("系统内部错误", ex); }
2. API 调用优化
📝 日志记录规范
// 操作前日志 _logger.LogInformation("开始执行操作: {Operation}, 参数: {@Parameters}", "CreateChatGroup", request); // 操作成功日志 _logger.LogInformation("操作执行成功: {Operation}, 结果: {Result}", "CreateChatGroup", result.Data?.ChatId); // 操作失败日志 _logger.LogError(ex, "操作执行失败: {Operation}, 错误: {Error}", "CreateChatGroup", ex.Message);
3. 生产环境注意事项
🔒 安全配置
- 将 AppSecret 存储在安全的位置
- 启用适当的日志级别
- 定期轮换应用密钥
📈 监控与告警
- 监控 API 调用成功率
- 设置异常率告警阈值
- 跟踪响应时间指标
🔄 重试策略
- 对于网络异常实现指数退避重试
- 区分可重试和不可重试的异常
- 避免对业务逻辑错误进行重试
Mud.Feishu 源码在 Gitee,遇到问题可以查看源码或提交 issue。