.NET 8+ 飞书API实战:自动化群组管理与消息推送

企业项目中经常需要批量操作飞书群组:项目启动时自动建群拉人、系统告警自动推送、员工入职离职自动处理群权限等。手动操作效率低且容易出错。

本文基于 Mud.Feishu ,从实际代码出发,讲解:

  • Tenant Access Token 获取机制
  • 聊天群组管理
  • 成员批量管理
  • 自动推送消息
  • 错误处理和重试策略

为什么需要服务端集成飞书?

典型的业务场景

在企业日常业务开展过程中,经常会遇到以下场景:

应用场景 核心功能 关键技术点 业务价值
项目群组自动化创建 - 新项目启动时自动创建项目群组 - 根据项目类型和人员角色批量拉入相关成员 - 设置群组名称、描述、权限等规范配置 - 群组创建API - 批量成员添加 - 权限模板配置 提高项目启动效率,确保团队沟通规范性
系统告警/通知自动推送 - 监控系统告警信息自动发送到指定飞书群 - 业务流程状态变更通知 - 定期报告和数据统计自动推送 - 富文本消息发送 - 定时任务调度 - 消息模板管理 及时通知相关人员,提升响应速度和决策效率
组织架构同步与批量管理 - HR系统组织架构变更同步到飞书 - 批量创建部门群组并同步成员 - 员工入职/离职时自动处理群组权限 - 组织架构API集成 - 批量群组管理 - 权限自动分配 保持组织架构一致性,减少人工维护成本

核心价值:服务端集成带来的优势

价值维度 核心特性 具体表现 技术优势
🚀 自动化 减少人工操作,提高工作效率 - 群组创建、成员管理、消息推送全流程自动化 - 7x24 小时无人值守运行 - 业务规则驱动的智能处理 程序化执行,减少人为错误,提升处理速度和一致性
🔧 业务解耦 独立于飞书客户端,可集成到现有系统 - 不依赖人工操作飞书客户端 - 与 ERP、HR、OA 等业务系统无缝集成 - API 接口标准化,易于扩展和维护 系统集成灵活,可嵌入现有工作流,降低耦合度
🛡️ 安全可靠 服务端级别的高可用性保障 - 企业级应用的认证和授权机制 - 操作日志完整记录,便于审计追踪 - 异常处理和重试机制,确保消息送达 企业级安全标准,操作可追溯,系统稳定性高

本文目标

实际解决企业中的几个问题:

  • ✅ Token 管理:获取、缓存、自动刷新机制
  • ✅ 群组操作:创建、查询、更新、解散
  • ✅ 成员管理:批量添加、移除、权限控制
  • ✅ 消息推送:文本、富文本、卡片等格式
  • ✅ 异常处理:错误码解析、重试策略、日志记录

准备工作:进入飞书开放平台

1. 创建应用

首先访问 飞书开放平台 并创建企业自建应用:

  1. 登录飞书开放平台

    • 使用企业管理员账号登录
    • 进入"开发者后台" -> "创建应用"
  2. 选择应用类型

    • 选择"企业自建应用"
    • 填写应用名称,如"企业群管系统"
    • 选择应用图标和描述
  3. 获取关键信息

    • 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. 发布与启用

  1. 应用发布

    • 确保应用状态为"已发布"
    • 配置应用图标、名称等基本信息
  2. 授权范围

    • 将应用授权给测试范围(如自己所在部门)
    • 生产环境需要管理员审批后才能全公司使用
  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: 返回业务数据

技术实现要点:

  1. 使用 App ID + App Secret 调用认证接口
  2. 获取 tenant_access_token 和过期时间
  3. 实现内存缓存,避免频繁请求认证接口
  4. Token 过期前自动刷新机制

2. 使用 Mud.Feishu 调用通用步骤

步骤概览

  1. 获取 Token:调用认证接口获取有效的访问令牌
  2. 构造请求:设置 HTTP 方法、URL、请求头等
  3. 携带认证:在请求头中添加 Bearer Token
  4. 处理请求体:构造 JSON 格式的请求参数
  5. 解析响应:处理 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。

相关推荐
烛阴2 小时前
从`new`关键字开始:精通C#类与对象
前端·c#
yangshuquan2 小时前
使用 C# + IronOcr,轻松实现图片文字自动识别(OCR)和提取
c#·ocr·编程技巧·winforms
天天代码码天天2 小时前
TSR18测速雷达C#对接
c#·雷达测速·tsr18测速雷达
道一232 小时前
C#获取操作系统版本号方法
开发语言·c#
道一233 小时前
C# 判断文件是否存在的方法
开发语言·c#
唐青枫4 小时前
C#.NET 范围与索引(Range、Index)完全解析:语法、用法与最佳实践
c#·.net
矶鹬笛手11 小时前
(2.1) 信息技术及其发展
sql·计算机网络·c#
u***276112 小时前
C#数据库操作系列---SqlSugar完结篇
网络·数据库·c#
笑非不退13 小时前
C# c++ 实现程序开机自启动
开发语言·c++·c#