You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过FileSystemWatcher与Incoming Webhook实现Teams通知推送

文件夹变更Teams通知问题修复与优化

核心问题排查

你的代码存在三个关键问题导致Teams通知失败:

  1. 推送时机错误:仅在程序启动时发送了一次POST请求,并未在文件创建/变更/删除等事件触发时执行推送逻辑
  2. JSON格式错误:Teams Webhook要求JSON使用双引号,你用了单引号;且$Created是无效变量,未关联实际事件信息
  3. 异步调用不规范:事件处理方法是同步方法,直接调用异步HTTP请求会引发线程管理问题

修正后的完整代码

using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

class FolderMonitor
{
    // 复用HttpClient,避免频繁创建连接
    private static readonly HttpClient _httpClient = new HttpClient();
    // 替换为你的Teams Incoming Webhook URL
    private const string TeamsWebhookUrl = "你的Teams Webhook地址";

    static async Task Main(string[] args)
    {
        if (args.Length == 0)
        {
            Console.WriteLine("请传入要监控的文件夹路径");
            return;
        }
        var monitorPath = args[0];

        using var watcher = new FileSystemWatcher(monitorPath);
        watcher.NotifyFilter = NotifyFilters.Attributes
                             | NotifyFilters.CreationTime
                             | NotifyFilters.DirectoryName
                             | NotifyFilters.FileName
                             | NotifyFilters.LastWrite
                             | NotifyFilters.Size;

        // 绑定异步事件处理方法
        watcher.Changed += OnChangedAsync;
        watcher.Created += OnCreatedAsync;
        watcher.Deleted += OnDeletedAsync;
        watcher.Renamed += OnRenamedAsync;
        watcher.Error += OnError;

        watcher.Filter = "";
        watcher.IncludeSubdirectories = false;
        watcher.EnableRaisingEvents = true;

        Console.WriteLine("监控已启动,按回车键退出。");
        Console.ReadLine();
    }

    private static async void OnChangedAsync(object sender, FileSystemEventArgs e)
    {
        if (e.ChangeType != WatcherChangeTypes.Changed)
            return;
        var message = $"文件已修改:{e.FullPath}";
        Console.WriteLine(message);
        await SendTeamsNotification(message);
    }

    private static async void OnCreatedAsync(object sender, FileSystemEventArgs e)
    {
        var message = $"文件已创建:{e.FullPath}";
        Console.WriteLine(message);
        await SendTeamsNotification(message);
    }

    private static async void OnDeletedAsync(object sender, FileSystemEventArgs e)
    {
        var message = $"文件已删除:{e.FullPath}";
        Console.WriteLine(message);
        await SendTeamsNotification(message);
    }

    private static async void OnRenamedAsync(object sender, RenamedEventArgs e)
    {
        var message = $"文件已重命名:\n旧路径:{e.OldFullPath}\n新路径:{e.FullPath}";
        Console.WriteLine(message);
        await SendTeamsNotification(message);
    }

    private static void OnError(object sender, ErrorEventArgs e) =>
        PrintException(e.GetException());

    private static async Task SendTeamsNotification(string text)
    {
        try
        {
            var payload = new { text = text };
            var json = JsonSerializer.Serialize(payload);
            var content = new StringContent(json, Encoding.UTF8, "application/json");

            var response = await _httpClient.PostAsync(TeamsWebhookUrl, content);
            response.EnsureSuccessStatusCode(); // 抛出HTTP错误状态码的异常
        }
        catch (Exception ex)
        {
            Console.WriteLine($"推送Teams通知失败:{ex.Message}");
            PrintException(ex.InnerException);
        }
    }

    private static void PrintException(Exception? ex)
    {
        if (ex != null)
        {
            Console.WriteLine($"异常信息:{ex.Message}");
            Console.WriteLine("调用栈:");
            Console.WriteLine(ex.StackTrace);
            Console.WriteLine();
            PrintException(ex.InnerException);
        }
    }
}

关键优化点说明

  1. 复用HttpClient:静态HttpClient实例避免了每次请求创建新连接的开销,符合.NET最佳实践
  2. 异步事件处理:将事件处理方法改为async void(仅适用于事件处理场景),确保HTTP请求异步执行不阻塞监控逻辑
  3. 正确的JSON序列化:使用System.Text.Json序列化对象,保证JSON格式符合Teams Webhook要求
  4. 异常处理:在推送方法中添加异常捕获,记录失败信息,避免监控逻辑崩溃
  5. 参数校验:启动时检查输入参数,避免空路径导致的错误

额外优化建议

  • 处理重复事件:FileSystemWatcher可能会对单个文件变更触发多次Changed事件,可通过记录文件最后修改时间来过滤重复通知
  • 配置化管理:将Webhook URL、监控路径等配置移到配置文件或环境变量,避免硬编码
  • 批量通知:如果短时间内有大量文件变更,可合并通知内容,避免Teams被刷屏
  • 日志集成:使用日志框架(如Serilog、NLog)替代Console.WriteLine,方便后期排查问题
  • 线程安全:如果需要在事件处理中操作共享资源,需添加线程同步机制(如lock)

内容的提问来源于stack exchange,提问作者Marck

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 18:05:23