包头市网站建设_网站建设公司_Windows Server_seo优化
2026/1/7 8:23:19 网站建设 项目流程

周末深夜,你收到紧急审批通知——却发现只能在 PC 端处理,只能摸黑起床开电脑……

这样的场景,你是否也经历过?

传统 .NET 系统与现代移动协同之间的鸿沟,正在悄悄吞噬着企业的效率。审批卡在桌面端、通知滞后、数据孤岛——这些问题让工作体验大打折扣。

推倒重来?成本太高,风险太大。

本文将带你走一条渐进式改造之路:保持 .NET 系统作为业务核心,将飞书审批作为移动门户,通过 API 实现无缝协同。从原理、设计到编码,完整呈现如何让传统系统焕发新生,实现移动化、实时化的现代化升级。

无论你是开发者、架构师还是技术管理者,都能收获一套可落地、可扩展的集成方案和直接复用的代码实践。

当传统业务遇上现代协同,为何必须"破壁"?

我们正在解决什么?

传统 .NET 系统的局限

许多企业拥有多年累积的 .NET 业务系统,这些系统在企业运营中扮演着核心角色。然而,随着移动办公和现代协同工具的普及,这些传统系统正面临着严峻的挑战:

痛点 具体表现 业务影响
审批流程封闭 审批只能在桌面端完成,无法随时随地处理 移动办公受阻,响应迟缓
通知方式滞后 依赖邮件或站内消息推送 审批人及时性差,流程延误
数据孤岛严重 审批数据与业务数据分离 无法形成完整的业务闭环
用户体验陈旧 界面风格陈旧,交互体验差 用户满意度低,使用意愿下降

飞书审批的赋能价值

飞书审批作为企业级的审批协作平台,为我们提供了一个理想的"流程协作中心":

graph LRA[飞书审批平台] --> B[移动优先]A --> C[即时强通知]A --> D[流程可视化]A --> E[完善审计日志]B --> B1[随时随地处理审批]C --> C1[App推送/短信提醒]D --> D1[拖拽式流程配置]E --> E1[完整操作痕迹追溯]

我们的核心目标

通过本文的实践,我们将建立 ".NET 系统为业务核心,飞书审批为流程门户" 的现代化混合架构:

架构愿景:将飞书审批作为统一的移动审批门户,保持 .NET 系统作为业务逻辑和数据存储的核心,通过 API 实时同步,形成优势互补的协同体系。

你将收获什么?

  • 一套端到端的集成方法论,覆盖从原理、设计到部署的全流程
  • 清晰的 .NET 侧架构蓝图,包含关键的技术选型与设计决策
  • 可直接复用的 C# 核心代码与实践中总结的"避坑指南"
  • 一个完整的"请假审批"实战案例,助你从零到一完成验证

飞书审批开放平台如何与我们"对话"?

双向集成的关键流程

飞书审批与 .NET 系统的集成是一个双向数据流的过程:

sequenceDiagramparticipant User as 用户participant NET as .NET系统participant API as 飞书APIparticipant FS as 飞书AppNote over User,FS: 流程输出:发起审批User->>NET: 1. 提交请假申请NET->>NET: 2. 保存业务数据(状态:审批中)NET->>API: 3. 调用 CreateInstanceAsyncAPI-->>NET: 4. 返回 instance_codeNET->>NET: 5. 关联业务ID与instance_codeNote over User,FS: 流程输入:回调通知User->>FS: 6. 在飞书App中审批FS->>API: 7. 审批完成API->>NET: 8. Webhook回调事件NET->>NET: 9. 根据instance_code更新业务状态

流程输出(发起阶段)

当用户在 .NET 系统发起审批时,系统会:

  1. 保存业务数据,状态标记为"审批中"
  2. 调用飞书 API CreateInstanceAsync 创建审批实例
  3. 接收返回的 instance_code,持久化到关联表

流程输入(回调阶段)

当审批人在飞书 App 完成审批后:

  1. 飞书服务器主动回调 .NET 系统的 Webhook 接口
  2. .NET 系统解析事件,提取 instance_codestatus
  3. 根据关联表查询对应的业务记录
  4. 更新业务状态,完成闭环

必须理解的三个核心概念

审批定义(approval_code)

审批定义是审批流程的"蓝图",在飞书管理后台配置:

// 示例:请假审批的审批定义
var approvalCode = "7C468A54-8745-2245-9675-08B7C63E7A85";

定义包含

  • 表单结构(请假类型、开始时间、结束时间、请假事由等)
  • 审批流程(直属主管审批 → 人事审批)
  • 权限设置(谁可以发起、谁可以审批)

审批实例(instance_code)

审批实例是依据审批定义发起的一次具体审批任务:

// 创建审批实例时返回
public record CreateInstancesResult
{/// <summary>/// 审批实例 Code/// </summary>[JsonPropertyName("instance_code")]public string InstanceCode { get; set; } = string.Empty;
}

关键属性

  • 唯一标识一次审批流程
  • 包含该次审批的所有表单数据
  • 拥有独立的状态(审批中、通过、拒绝、撤回等)

身份映射(免登)

实现 .NET 系统用户与飞书用户的关联:

graph LRA[.NET系统用户<br/>UserId: 1001] -->|映射关系| B[飞书用户<br/>OpenId: ou_3cda9c...]B -->|通过飞书App审批| C[审批完成]C -->|回调instance_code| A

实现方式

  1. 在 .NET 系统的用户表中添加 FeishuOpenId 字段
  2. 用户首次登录时进行飞书免登录认证,获取并存储 open_id
  3. 发起审批时,使用 open_id 指定审批发起人

构建稳健、可扩展的 .NET 侧集成层

技术栈推荐

层次 技术选型 说明
应用框架 .NET 6/8/10 长期支持版本,性能优异
飞书 SDK Mud.Feishu 高度封装的飞书 API 客户端
Webhook 处理 Mud.Feishu.Webhook 飞书事件回调处理组件
认证授权 ASP.NET Core Identity / JWT 内部系统身份管理
异步解耦 RabbitMQ / Hangfire 回调消息队列处理,提升可靠性
数据存储 SQL Server / PostgreSQL 业务数据 + 审批关联表

分层架构图

graph TBsubgraph "表示层 (UI)"A[Web 前端 / 移动端]endsubgraph "应用层 (API)"B[LeaveController]C[FeishuWebhookController]endsubgraph "领域层 (业务逻辑)"D[ILeaveService]E[ApprovalIntegrationService]F[IApprovalService]endsubgraph "基础设施层"G[Mud.Feishu HTTP客户端]H[Mud.Feishu.Webhook处理器]I[数据仓储<br/>EF Core]endA --> BA --> CB --> DC --> ED --> FE --> FF --> GF --> HF --> I

关键设计:领域层抽象

在领域层引入 IApprovalService 接口,将飞书集成细节与核心业务逻辑解耦:

/// <summary>
/// 审批服务抽象接口 - 解耦飞书实现细节
/// </summary>
public interface IApprovalService
{/// <summary>/// 发起审批/// </summary>Task<string> CreateApprovalAsync(ApprovalRequest request);/// <summary>/// 处理审批结果回调/// </summary>Task HandleApprovalCallbackAsync(ApprovalCallbackEvent callbackEvent);
}/// <summary>
/// 飞书审批服务实现
/// </summary>
public class FeishuApprovalService : IApprovalService
{private readonly IFeishuTenantV4Approval _approvalApi;private readonly IApprovalRecordRepository _repository;public FeishuApprovalService(IFeishuTenantV4Approval approvalApi,IApprovalRecordRepository repository){_approvalApi = approvalApi;_repository = repository;}public async Task<string> CreateApprovalAsync(ApprovalRequest request){// 调用飞书 APIvar result = await _approvalApi.CreateInstanceAsync(...);return result.Data?.InstanceCode ?? string.Empty;}
}

优势

  • 业务逻辑不依赖具体飞书实现
  • 便于单元测试(可 Mock 接口)
  • 未来可轻松切换到其他审批平台

实战:手把手完成"请假审批"集成

第一步:飞书平台侧配置(审批流出口)

创建企业自建应用

登录飞书开放平台(https://open.feishu.cn),进入应用管理:

graph LRA[创建自建应用] --> B[获取App ID]A --> C[获取App Secret]B --> D[配置到.NET系统]C --> D

关键配置

  • 记录 App IDApp Secret
  • 配置应用权限:审批相关权限(approval:approval:read, approval:instance:read, approval:instance:create

配置审批定义

在飞书管理后台创建"请假审批"模板:

graph LRA[审批定义配置] --> B[表单设置]A --> C[流程设置]A --> D[权限设置]B --> B1[请假类型<br/>开始时间<br/>结束时间<br/>请假天数<br/>请假事由]C --> C1[直属主管审批<br/>→ 人事审批]D --> D1[全员可发起]

记录关键信息

  • approval_code:审批定义的唯一标识
  • 表单控件的 id:用于程序填充表单数据

配置事件订阅

在飞书开放平台配置 Webhook:

配置项
请求网址 https://your-domain.com/api/feishu/webhook
验证 Token your_verification_token(自定义)
加密 Key your_encrypt_key(自定义)
订阅事件 approval_instance(审批实例状态变更)

第二步:.NET 侧基础搭建(集成基石)

封装飞书 API 客户端

基于 MudFeishu SDK 封装审批服务:

/// <summary>
/// 飞书审批服务封装
/// </summary>
public class FeishuApprovalClient
{private readonly IFeishuTenantV4Approval _approvalApi;private readonly ILogger<FeishuApprovalClient> _logger;public FeishuApprovalClient(IFeishuTenantV4Approval approvalApi,ILogger<FeishuApprovalClient> logger){_approvalApi = approvalApi;_logger = logger;}/// <summary>/// 创建审批实例/// </summary>public async Task<string> CreateInstanceAsync(CreateInstanceRequest request){var result = await _approvalApi.CreateInstanceAsync(request);if (result == null || result.Code != 0){_logger.LogError("创建审批实例失败: {Msg}", result?.Msg);throw new InvalidOperationException($"创建审批实例失败: {result?.Msg}");}_logger.LogInformation("创建审批实例成功: {InstanceCode}", result.Data?.InstanceCode);return result.Data?.InstanceCode ?? string.Empty;}/// <summary>/// 获取审批实例详情/// </summary>public async Task<GetApprovalInstanceResult?> GetInstanceAsync(string instanceCode){var result = await _approvalApi.GetInstanceByIdAsync(instanceCode);if (result == null || result.Code != 0){_logger.LogError("获取审批实例失败: {Msg}", result?.Msg);return null;}return result.Data;}
}

设计数据关联表

在业务数据库中添加审批关联表:

-- 审批关联表
CREATE TABLE ApprovalRecords (Id BIGINT PRIMARY KEY IDENTITY(1,1),BusinessType NVARCHAR(50) NOT NULL,          -- 业务类型:LeaveRequest, PurchaseRequest...BusinessId BIGINT NOT NULL,                   -- 业务IDInstanceCode NVARCHAR(64) NOT NULL,           -- 飞书审批实例CodeApprovalCode NVARCHAR(64) NOT NULL,            -- 审批定义CodeStatus NVARCHAR(20) NOT NULL,                  -- 状态:PENDING, APPROVED, REJECTED...CallbackData NVARCHAR(MAX),                   -- 回调数据(JSON)CreatedTime DATETIME2 NOT NULL DEFAULT GETUTCDATE(),UpdatedTime DATETIME2 NOT NULL DEFAULT GETUTCDATE(),CONSTRAINT UK_ApprovalRecords_Business UNIQUE(BusinessType, BusinessId)
);CREATE INDEX IX_ApprovalRecords_InstanceCode ON ApprovalRecords(InstanceCode);
CREATE INDEX IX_ApprovalRecords_Status ON ApprovalRecords(Status);

对应的实体类:

/// <summary>
/// 审批关联记录
/// </summary>
public class ApprovalRecord
{public long Id { get; set; }public string BusinessType { get; set; } = string.Empty;  // "LeaveRequest"public long BusinessId { get; set; }                       // 请假申请IDpublic string InstanceCode { get; set; } = string.Empty;   // 飞书实例Codepublic string ApprovalCode { get; set; } = string.Empty;    // 审批定义Codepublic string Status { get; set; } = string.Empty;         // PENDING/APPROVED/REJECTEDpublic string? CallbackData { get; set; }                  // JSON格式public DateTime CreatedTime { get; set; }public DateTime UpdatedTime { get; set; }
}

第三步:核心业务流程编码(双向联通)

场景:用户提交请假单,发起审批

流程图

sequenceDiagramparticipant User as 用户participant Controller as LeaveControllerparticipant Service as LeaveServiceparticipant DB as 数据库participant FeishuAPI as 飞书APIUser->>Controller: 提交请假申请Controller->>Service: SubmitLeaveRequest(request)Service->>DB: 保存请假记录(状态:审批中)Service->>Service: 构造表单数据Service->>FeishuAPI: CreateInstanceAsync(approvalCode, form)FeishuAPI-->>Service: instance_codeService->>DB: 保存ApprovalRecord关联Service-->>Controller: 提交成功Controller-->>User: 等待审批

代码实现

/// <summary>
/// 请假服务
/// </summary>
public class LeaveService
{private readonly ILeaveRequestRepository _leaveRepo;private readonly IApprovalRecordRepository _approvalRepo;private readonly FeishuApprovalClient _feishuClient;private readonly ILogger<LeaveService> _logger;public LeaveService(ILeaveRequestRepository leaveRepo,IApprovalRecordRepository approvalRepo,FeishuApprovalClient feishuClient,ILogger<LeaveService> logger){_leaveRepo = leaveRepo;_approvalRepo = approvalRepo;_feishuClient = feishuClient;_logger = logger;}/// <summary>/// 提交请假申请并发起审批/// </summary>public async Task<long> SubmitLeaveRequestAsync(SubmitLeaveRequestDto dto){// 1. 保存请假业务数据var leaveRequest = new LeaveRequest{UserId = dto.UserId,LeaveType = dto.LeaveType,StartTime = dto.StartTime,EndTime = dto.EndTime,Days = dto.Days,Reason = dto.Reason,Status = LeaveStatus.Pending,  // 审批中CreatedTime = DateTime.UtcNow};await _leaveRepo.AddAsync(leaveRequest);await _leaveRepo.SaveChangesAsync();// 2. 构造飞书审批表单数据var form = new List<object>{new { id = "leave_type", type = "select", value = dto.LeaveType },new { id = "start_time", type = "date", value = dto.StartTime.ToString("yyyy-MM-dd") },new { id = "end_time", type = "date", value = dto.EndTime.ToString("yyyy-MM-dd") },new { id = "days", type = "number", value = dto.Days.ToString() },new { id = "reason", type = "textarea", value = dto.Reason }};// 3. 调用飞书API创建审批实例var request = new CreateInstanceRequest{ApprovalCode = "7C468A54-8745-2245-9675-08B7C63E7A85",  // 请假审批定义CodeUserId = dto.FeishuUserId,  // 飞书用户IDForm = JsonSerializer.Serialize(form),Uuid = Guid.NewGuid().ToString()  // 幂等ID};string instanceCode;try{instanceCode = await _feishuClient.CreateInstanceAsync(request);}catch (Exception ex){_logger.LogError(ex, "创建飞书审批实例失败");// 回滚业务数据leaveRequest.Status = LeaveStatus.Failed;await _leaveRepo.SaveChangesAsync();throw;}// 4. 保存审批关联记录var approvalRecord = new ApprovalRecord{BusinessType = "LeaveRequest",BusinessId = leaveRequest.Id,InstanceCode = instanceCode,ApprovalCode = request.ApprovalCode,Status = "PENDING",CreatedTime = DateTime.UtcNow,UpdatedTime = DateTime.UtcNow};await _approvalRepo.AddAsync(approvalRecord);await _approvalRepo.SaveChangesAsync();_logger.LogInformation("请假申请已提交并创建审批: LeaveId={LeaveId}, InstanceCode={InstanceCode}",leaveRequest.Id, instanceCode);return leaveRequest.Id;}
}

场景:审批完结,飞书回调通知结果

基于 Mud.Feishu.Webhook 实现安全的回调处理器

using Mud.Feishu.Abstractions;
using Mud.Feishu.Abstractions.DataModels.Approval;
using Mud.Feishu.Abstractions.EventHandlers;/// <summary>
/// 审批实例事件处理器
/// </summary>
public class ApprovalInstanceEventHandler : ApprovalInstanceEventHandler
{private readonly IApprovalRecordRepository _approvalRepo;private readonly ILeaveRequestRepository _leaveRepo;public ApprovalInstanceEventHandler(ILogger<ApprovalInstanceEventHandler> logger,IApprovalRecordRepository approvalRepo,ILeaveRequestRepository leaveRepo): base(logger){_approvalRepo = approvalRepo;_leaveRepo = leaveRepo;}/// <summary>/// 处理审批实例事件业务逻辑/// </summary>protected override async Task ProcessBusinessLogicAsync(EventData eventData,ObjectEventResult<ApprovalInstanceResult>? eventEntity,CancellationToken cancellationToken = default){if (eventEntity?.Object == null){_logger.LogWarning("审批实例事件数据无效");return;}var approvalEvent = eventEntity.Object;_logger.LogInformation("收到审批实例事件: InstanceCode={InstanceCode}, Status={Status}",approvalEvent.InstanceCode, approvalEvent.Status);// 幂等性处理:检查是否已处理过该事件var existingRecord = await _approvalRepo.GetByInstanceCodeAsync(approvalEvent.InstanceCode ?? string.Empty);if (existingRecord != null && existingRecord.Status == approvalEvent.Status){_logger.LogInformation("该事件已处理过,跳过: EventId={EventId}", eventData.EventId);return;}// 根据业务类型处理审批结果await ProcessApprovalResultAsync(eventData, approvalEvent, cancellationToken);}/// <summary>/// 处理审批结果/// </summary>private async Task ProcessApprovalResultAsync(EventData eventData,ApprovalInstanceResult approvalEvent,CancellationToken cancellationToken){if (string.IsNullOrEmpty(approvalEvent.InstanceCode)){_logger.LogWarning("审批实例Code为空,跳过处理");return;}// 查询审批关联记录var approvalRecord = await _approvalRepo.GetByInstanceCodeAsync(approvalEvent.InstanceCode);if (approvalRecord == null){_logger.LogWarning("未找到审批关联记录: InstanceCode={InstanceCode}",approvalEvent.InstanceCode);return;}// 更新审批记录状态approvalRecord.Status = approvalEvent.Status ?? string.Empty;approvalRecord.CallbackData = JsonSerializer.Serialize(approvalEvent);approvalRecord.UpdatedTime = DateTime.UtcNow;await _approvalRepo.SaveChangesAsync();// 根据业务类型处理switch (approvalRecord.BusinessType){case "LeaveRequest":await ProcessLeaveApprovalAsync(approvalRecord, approvalEvent.Status ?? string.Empty);break;// 可扩展其他业务类型default:_logger.LogWarning("未知的业务类型: {BusinessType}", approvalRecord.BusinessType);break;}}/// <summary>/// 处理请假审批结果/// </summary>private async Task ProcessLeaveApprovalAsync(ApprovalRecord approvalRecord, string status){var leaveRequest = await _leaveRepo.GetByIdAsync(approvalRecord.BusinessId);if (leaveRequest == null){_logger.LogWarning("未找到请假申请: BusinessId={BusinessId}", approvalRecord.BusinessId);return;}// 根据审批状态更新请假记录leaveRequest.Status = status switch{"APPROVED" => LeaveStatus.Approved,"REJECTED" => LeaveStatus.Rejected,"CANCELED" => LeaveStatus.Canceled,"DELETED" => LeaveStatus.Deleted,_ => LeaveStatus.Pending};leaveRequest.UpdatedTime = DateTime.UtcNow;await _leaveRepo.SaveChangesAsync();_logger.LogInformation("请假申请状态已更新: LeaveId={LeaveId}, Status={Status}",leaveRequest.Id, leaveRequest.Status);// TODO: 发送通知给申请人// TODO: 同步到考勤系统}
}

注册 Webhook 服务(Program.cs)

using Mud.Feishu.Webhook;
using Mud.Feishu;
using YourApp.Handlers;var builder = WebApplication.CreateBuilder(args);// 注册飞书 API 服务
builder.Services.AddFeishuServices().ConfigureFrom(builder.Configuration)  // 从 "Feishu" 配置节读取.Build();// 注册飞书 Webhook 事件订阅服务
builder.Services.AddFeishuWebhookServiceBuilder().ConfigureFrom(builder.Configuration)  // 从 "FeishuWebhook" 配置节读取.AddHandler<ApprovalInstanceEventHandler>()  // 添加审批事件处理器.Build();// 注册业务服务
builder.Services.AddScoped<ILeaveRequestRepository, LeaveRequestRepository>();
builder.Services.AddScoped<IApprovalRecordRepository, ApprovalRecordRepository>();var app = builder.Build();app.UseFeishuWebhook();  // 添加 Webhook 中间件app.Run();

说明

  • ApprovalInstanceEventHandler 继承自 ApprovalInstanceEventHandler 基类
  • 基类已经实现了 HandleAsync 方法,会自动反序列化 ApprovalInstanceResult 类型的事件数据
  • 只需重写 ProcessBusinessLogicAsync 方法实现具体的业务逻辑即可
  • SDK 会根据 SupportedEventType 属性自动路由对应的事件到这个处理器
  • AddFeishuServices() 注册飞书 API 客户端服务,使用 Feishu 配置节
  • AddFeishuWebhookServiceBuilder() 注册 Webhook 事件订阅服务,使用 FeishuWebhook 配置节

配置文件(appsettings.json)

{// 飞书 Webhook 事件订阅配置"FeishuWebhook": {"VerificationToken": "your_verification_token","EncryptKey": "your_encrypt_key","RoutePrefix": "api/feishu/webhook","AutoRegisterEndpoint": true,"EnableRequestLogging": true,"EnableExceptionHandling": true,"EventHandlingTimeoutMs": 30000,"MaxConcurrentEvents": 10},// 飞书 API 客户端配置"Feishu": {"AppId": "your_app_id","AppSecret": "your_app_secret","BaseUrl": "https://open.feishu.cn","TimeOut": "30","RetryCount": 3,"EnableLogging": true}
}

第四步:功能完善与联调测试

状态同步展示

在请假列表页展示审批状态:

/// <summary>
/// 请假列表响应DTO
/// </summary>
public class LeaveRequestDto
{public long Id { get; set; }public DateTime StartTime { get; set; }public DateTime EndTime { get; set; }public int Days { get; set; }public string Status { get; set; } = string.Empty;      // 业务状态:Approved, Rejectedpublic string ApprovalStatus { get; set; } = string.Empty; // 飞书审批状态:APPROVED, REJECTED, PENDINGpublic string? FeishuInstanceUrl { get; set; }          // 飞书审批详情链接public DateTime CreatedTime { get; set; }
}/// <summary>
/// 查询请假列表
/// </summary>
public async Task<List<LeaveRequestDto>> GetLeaveListAsync(long userId)
{var leaves = await _leaveRepo.GetByUserIdAsync(userId);var instanceCodes = leaves.Select(l => l.InstanceCode).ToList();// 批量查询审批记录var approvals = await _approvalRepo.GetByInstanceCodesAsync(instanceCodes);var result = leaves.Select(leave =>{var approval = approvals.FirstOrDefault(a => a.InstanceCode == leave.InstanceCode);return new LeaveRequestDto{Id = leave.Id,StartTime = leave.StartTime,EndTime = leave.EndTime,Days = leave.Days,Status = leave.Status.ToString(),ApprovalStatus = approval?.Status ?? "UNKNOWN",FeishuInstanceUrl = !string.IsNullOrEmpty(approval?.InstanceCode)? $"https://www.feishu.cn/approval/approval/view/{approval.InstanceCode}": null,CreatedTime = leave.CreatedTime};}).ToList();return result;
}

添加"在飞书中查看"链接

在列表页添加操作按钮:

<!-- 前端页面示例 -->
<table class="leave-list"><thead><tr><th>开始时间</th><th>结束时间</th><th>天数</th><th>审批状态</th><th>操作</th></tr></thead><tbody>@foreach (var leave in Model.Leaves){<tr><td>@leave.StartTime.ToString("yyyy-MM-dd")</td><td>@leave.EndTime.ToString("yyyy-MM-dd")</td><td>@leave.Days</td><td><span class="status @leave.ApprovalStatus">@GetStatusText(leave.ApprovalStatus)</span></td><td>@if (!string.IsNullOrEmpty(leave.FeishuInstanceUrl)){<a href="@leave.FeishuInstanceUrl" target="_blank" class="btn">在飞书中查看</a>}</td></tr>}</tbody>
</table>

联调测试

测试场景 验证要点 测试工具
发起审批 飞书是否收到审批通知、表单数据是否正确 直接在系统发起
审批流程 各审批节点是否正确流转 飞书管理后台
回调接收 Webhook是否正确接收事件、数据是否完整 飞书"模拟事件推送"工具
状态同步 业务状态是否正确更新、通知是否发送 数据库查询、日志查看
异常处理 网络异常、签名验证失败等边界情况 模拟异常场景

飞书模拟事件推送工具

在飞书开放平台的"事件订阅"页面,可以使用"模拟事件推送"功能测试 Webhook 接口:

graph LRA[飞书管理后台] -->|模拟事件推送| B[Webhook接口]B -->|日志输出| C[检查处理结果]C -->|成功| D[验证完成]C -->|失败| E[查看错误日志]

生产级注意事项

安全与可靠性

机密管理

切勿将敏感信息硬编码在代码中!

// ❌ 错误示例
var appSecret = "cli_xxxxxxxxxxxxxxx";  // 危险!// ✅ 正确示例
builder.Configuration.AddAzureKeyVault(new Uri($"https://{vaultName}.vault.azure.net/"),new DefaultAzureCredential());var appSecret = builder.Configuration["Feishu:AppSecret"];

推荐方案

  • Azure Key Vault / AWS Secrets Manager
  • HashiCorp Vault
  • Docker Secrets(容器化部署)

幂等性处理

飞书可能会重复推送同一个事件(网络重试等),必须保证业务逻辑的幂等性:

public async Task HandleAsync(EventData eventData, CancellationToken cancellationToken = default)
{// 使用 EventId 或 instance_code + status 组合作为幂等键var idempotencyKey = $"{approvalEvent.InstanceCode}_{approvalEvent.Status}";// 检查是否已处理过if (await _cache.ExistsAsync(idempotencyKey)){_logger.LogInformation("事件已处理过,跳过: Key={IdempotencyKey}", idempotencyKey);return;}// 标记为已处理(设置过期时间,如24小时)await _cache.SetAsync(idempotencyKey, "1", TimeSpan.FromHours(24));// 执行业务逻辑await ProcessEventAsync(approvalEvent, cancellationToken);
}

API 容错

使用 Polly 为飞书 API 调用添加重试和熔断机制:

// 注册 HttpClient 时添加 Polly 策略
builder.Services.AddHttpClient("Feishu").AddTransientHttpErrorPolicy(p =>p.WaitAndRetryAsync(3, retryAttempt =>TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)))).AddPolicyHandler(Policy<HttpResponseMessage>.Handle<HttpRequestException>().CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)));

边界情况与优雅降级

审批人失效处理

// 飞书审批定义中配置默认审批人
var request = new CreateInstanceRequest
{ApprovalCode = "xxxx",// 如果自选审批人为空,使用默认审批人NodeApproverUserIdLists = dto.ApproverUserId.HasValue? new[] { new NodeApprover { NodeId = "node1", ApproverUserIds = new[] { dto.ApproverUserId.Value } } }: null  // 走默认审批人流程
};

网络超时与异步处理

回调处理应快速响应飞书(建议在 3 秒内),复杂逻辑移至后台作业:

public async Task HandleAsync(EventData eventData, CancellationToken cancellationToken = default)
{// 1. 快速保存事件到队列await _eventQueue.EnqueueAsync(eventData);// 2. 立即返回,由后台作业处理// Hangfire、RabbitMQ 等会异步消费队列await Task.CompletedTask;
}// 后台作业处理
[Queue("approval-callback")]
public async Task ProcessApprovalEventAsync(EventData eventData)
{// 复杂的业务逻辑处理await _approvalService.ProcessCallbackAsync(eventData);
}

监控与告警

建立关键节点的监控:

// 监控指标
public class ApprovalMetrics
{private readonly Counter _approvalCreatedCounter;private readonly Counter _callbackReceivedCounter;private readonly Histogram _processingTimeHistogram;public void RecordApprovalCreated(string approvalType){_approvalCreatedCounter.WithLabels(approvalType).Inc();}public void RecordCallbackReceived(string status){_callbackReceivedCounter.WithLabels(status).Inc();}public void RecordProcessingTime(TimeSpan duration){_processingTimeHistogram.Observe(duration.TotalSeconds);}
}// 告警规则(Prometheus 示例)
# 审批发起失败率超过 5% 触发告警
alert: ApprovalCreationFailureRate
expr: rate(approval_creation_failed_total[5m]) / rate(approval_creation_total[5m]) > 0.05
for: 5m
annotations:summary: "审批创建失败率过高"

扩展性与维护性

策略模式支持多平台

/// <summary>
/// 审批平台策略接口
/// </summary>
public interface IApprovalPlatformStrategy
{string PlatformName { get; }Task<string> CreateInstanceAsync(ApprovalRequest request);
}/// <summary>
/// 飞书审批策略
/// </summary>
public class FeishuApprovalStrategy : IApprovalPlatformStrategy
{public string PlatformName => "Feishu";// ... 实现
}/// <summary>
/// 钉钉审批策略
/// </summary>
public class DingTalkApprovalStrategy : IApprovalPlatformStrategy
{public string PlatformName => "DingTalk";// ... 实现
}/// <summary>
/// 审批策略工厂
/// </summary>
public class ApprovalStrategyFactory
{private readonly IEnumerable<IApprovalPlatformStrategy> _strategies;public IApprovalPlatformStrategy GetStrategy(string platformName){return _strategies.FirstOrDefault(s => s.PlatformName == platformName)?? throw new NotSupportedException($"不支持的审批平台: {platformName}");}
}

审计日志

详细记录审批流转换的关键日志:

public class ApprovalAuditService
{private readonly IApprovalAuditRepository _auditRepo;public async Task LogAsync(ApprovalAuditLog log){log.Timestamp = DateTime.UtcNow;await _auditRepo.AddAsync(log);await _auditRepo.SaveChangesAsync();// 结构化日志输出_logger.LogInformation("审批审计: {AuditType}, InstanceCode={InstanceCode}, BusinessId={BusinessId}",log.AuditType, log.InstanceCode, log.BusinessId);}
}// 使用示例
await _auditService.LogAsync(new ApprovalAuditLog
{AuditType = "ApprovalStarted",InstanceCode = instanceCode,BusinessId = leaveRequest.Id,OperatorId = userId,Details = new { leaveType, days, reason }
});

最后一点内容

核心价值

通过本文的实践,我们成功实现了:

价值点 实现方式 收益
移动化审批 飞书 App 作为审批门户 随时随地处理审批
即时通知 飞书强通知机制 审批人及时响应
数据闭环 .NET 业务库 + 审批关联表 完整的业务流程追踪
解耦设计 领域层抽象 + 策略模式 便于扩展和维护

全文总结

本文提供了一个从理念、设计到编码落地的完整闭环:

mindmaproot((飞书审批集成))理念双向集成.NET为业务核心飞书为流程门户设计分层架构领域抽象安全机制实现发起审批回调处理状态同步最佳实践机密管理幂等性异步处理监控告警

扩展

场景扩展

将此模式快速复用于其他业务场景:

业务场景 审批流程 复杂度
报销审批 发起 → 直属主管 → 财务审核
采购申请 发起 → 部门主管 → 采购部 → 总经理
合同审批 法务审核 → 财务审核 → 总经理
加班申请 直属主管审批

深度集成

利用飞书更多能力,打造更丰富的协同体验:

graph TBA[飞书审批] --> B[消息卡片]A --> C[智能机器人]A --> D[知识库]B --> B1[审批详情展示]B --> B2[操作按钮]C --> C1[智能提醒]C --> C2[自动补全]D --> D1[历史记录查询]D --> D2[审批规范]E[.NET系统] --> AB --> EC --> ED --> E

功能扩展示例

  • 在飞书群聊中通过消息卡片直接查看审批详情
  • 通过机器人智能回复,引导用户填写审批表单
  • 将审批记录同步到飞书知识库,方便查阅

平台化

将审批集成能力抽象为中台服务,供企业内部所有系统统一调用:

/// <summary>
/// 统一审批服务中台
/// </summary>
public interface IApprovalCenterService
{/// <summary>/// 统一发起审批(支持多平台)/// </summary>Task<string> CreateApprovalAsync(UnifiedApprovalRequest request);/// <summary>/// 查询审批状态/// </summary>Task<ApprovalStatus> GetStatusAsync(string instanceId);/// <summary>/// 审批统计报表/// </summary>Task<ApprovalStatistics> GetStatisticsAsync(DateTime from, DateTime to);
}// 多个系统统一调用
await _approvalCenter.CreateApprovalAsync(new UnifiedApprovalRequest
{BusinessSystem = "HR",BusinessType = "LeaveRequest",BusinessId = leaveId,Platform = "Feishu"  // 可切换到其他平台
});

结语

传统 .NET 系统无需推倒重来,通过合理的架构设计与飞书审批的深度集成,同样可以焕发新的活力。希望本文的实践能够为你的数字化转型之路提供有价值的参考。

让我们一起告别信息孤岛,拥抱现代化的协同办公体验!🚀


相关资源

项目地址

  • Gitee 仓库:https://gitee.com/mudtools/MudFeishu

  • GitHub 仓库:https://github.com/mudtools/MudFeishu

  • NuGet 包

    • Mud.Feishu.Abstractions

    • Mud.Feishu

    • Mud.Feishu.WebSocket

    • Mud.Feishu.Webhook

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询