C# 中如何记录未捕获的异常?

C# 记录未捕获异常:订阅 AppDomain.UnhandledException 事件记录全局异常,TaskScheduler.UnobservedTaskException 处理异步任务异常。本文给出完整实现。

最佳实践
C# 中如何记录未捕获的异常?封面

核心:在程序入口订阅 AppDomain.CurrentDomain.UnhandledException 事件,在回调中用日志框架(如 NLog/log4net)记录异常详情,尽力在进程终止前留下错误信息,但不能保证缓冲日志全部落盘。

完整实现

using System;
using System.Threading.Tasks;
using NLog;

class Program
{
    private static readonly Logger Logger = LogManager.GetCurrentClassLogger();

    static void Main(string[] args)
    {
        // 订阅全局未捕获异常事件
        AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
        {
            var ex = e.ExceptionObject as Exception;
            Logger.Fatal(ex, "未捕获的异常导致程序崩溃");
        };

        // 捕获异步任务中未观察到的异常
        TaskScheduler.UnobservedTaskException += (sender, e) =>
        {
            Logger.Error(e.Exception, "异步任务中出现未处理的异常");
            e.SetObserved();  // 标记为已观察;现代 .NET 默认不会因未观察任务异常终止
        };

        // 正常业务逻辑...
    }
}

ASP.NET Core 的方式

// ASP.NET Core Program.cs;app 为 WebApplication
// 需引入 Microsoft.AspNetCore.Diagnostics、Microsoft.AspNetCore.Http
// 与 Microsoft.Extensions.Logging
app.UseExceptionHandler(errorApp =>
{
    errorApp.Run(async context =>
    {
        var feature = context.Features.Get<IExceptionHandlerFeature>();
        app.Logger.LogError(feature?.Error, "未处理的请求异常");
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        await context.Response.WriteAsync("服务器内部错误");
    });
});

常见问题(FAQ)

Q:.NET Core / .NET 5+ 还需要 AppDomain 事件吗?
A:仍然有效,但 ASP.NET Core 更推荐用中间件(ExceptionHandlerMiddleware)统一处理请求管道中的异常。

Q:async/await 中的异常能被 UnhandledException 捕获吗?
A:async Task 的异常保存在 Task 中,await 时重新抛出,应在调用边界捕获。未观察异常事件可能延迟到垃圾回收时发生,不能替代 await;async void 的传播方式不同,也可能成为未处理异常。

Q:记录完异常后程序会继续运行吗?
A:UnhandledException 触发时进程已经在终止过程中,你只能记录日志、不能做恢复操作。现代 .NET 默认不会因未观察 Task 异常终止;SetObserved() 用于标记已观察,旧运行时或显式升级策略需另行核对。

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台