企业项目中经常需要批量操作飞书群组:项目启动时自动建群拉人、系统告警自动推送、员工入职离职自动处理群权限等。手动操作效率低且容易出错。
本文基于 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 重新获取
获取流程详解
sequenceDiagram participant App as .NET应用 participant Feishu as 飞书API participant DB as 内存缓存 App->>DB: 检查缓存中的Token alt Token存在且未过期 DB-->>App: 返回缓存的Token else Token不存在或已过期 App->>Feishu: POST /open-apis/auth/v3/tenant_access_token/internal Note right of Feishu: 携带App ID和App Secret Feishu-->>App: 返回tenant_access_token App->>DB: 缓存新Token end App->>Feishu: 调用业务API (携带Token) Note over App,Feishu: Authorization: Bearer {tenant_access_token} Feishu-->>App: 返回业务数据
技术实现要点:
- 使用
App ID + App Secret调用认证接口 - 获取
tenant_access_token和过期时间 - 实现内存缓存,避免频繁请求认证接口
- Token 过期前自动刷新机制
2. 使用 Mud.Feishu 调用通用步骤
步骤概览
- 获取 Token:调用认证接口获取有效的访问令牌
- 构造请求:设置 HTTP 方法、URL、请求头等
- 携带认证:在请求头中添加 Bearer Token
- 处理请求体:构造 JSON 格式的请求参数
- 解析响应:处理 API 返回的 JSON 响应数据
简化的调用流程
csharp
// 传统方式 - 需要大量样板代码
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. 环境与项目搭建
创建新项目
bash
# 创建 .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:
json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"Feishu": {
"AppId": "cli_xxxxxxxxxxxxxxxx",
"AppSecret": "your_secret_key_here",
"BaseUrl": "https://open.feishu.cn"
}
}
服务注册配置
在 Program.cs 中注册飞书服务:
csharp
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 调用:
csharp
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 内置了自动令牌管理,但我们可以展示手动获取的过程:
csharp
/// <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,供后续操作使用
csharp
/// <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响应,包含错误检查和异常处理
- 记录获取到的群组数量,便于监控和调试
- 返回包含群组列表和分页信息的完整结果
- 支持继续分页查询,可用于群组数据的批量处理
csharp
/// <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响应,包含错误检查和异常处理
- 记录操作成功日志,便于追踪群组访问情况
- 返回完整的群组详情对象,包含所有群组属性
- 支持异常传播,确保调用方能正确处理错误情况
csharp
/// <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执行群组信息更新操作
- 处理更新结果,包含错误检查和异常处理
- 记录更新操作日志,便于审计和追踪
- 返回布尔值指示更新操作是否成功完成
csharp
/// <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列表的详细结果,便于后续处理
csharp
/// <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执行群组解散操作
- 注意:此操作不可逆,解散后群组将永久删除
- 处理解散结果,包含错误检查和异常处理
- 记录关键操作日志,便于审计和追踪解散行为
- 返回布尔值指示解散操作是否成功完成
- 确保只有有权限的用户才能执行此敏感操作
csharp
/// <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追踪:返回消息唯一标识符,便于后续操作
- 日志记录:详细的发送操作日志,便于监控和调试
csharp
/// <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}\n\n{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 来演示完整业务流程:
csharp
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;
}
完整业务流程演示
csharp
/// <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 处理策略
csharp
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 调用优化
📝 日志记录规范
csharp
// 操作前日志
_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。