C# 中如何记录未捕获的异常?
C# 记录未捕获异常:订阅 AppDomain.UnhandledException 事件记录全局异常,TaskScheduler.UnobservedTaskException 处理异步任务异常。本文给出完整实现。
核心:在程序入口订阅 AppDomain.CurrentDomain.UnhandledException 事件,在回调中用日志框架(如 NLog/log4net)记录异常详情,确保进程崩溃前留下完整的错误信息。
完整实现
using System;
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(); // 标记为已处理,防止进程崩溃
};
// 正常业务逻辑...
}
}
ASP.NET Core 的方式
// Program.cs / Startup.cs
app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
var feature = context.Features.Get<IExceptionHandlerFeature>();
logger.LogError(feature?.Error, "未处理的请求异常");
await context.Response.WriteAsync("服务器内部错误");
});
});
观测云对照
观测云 APM 通过探针自动捕获 .NET 应用中的未处理异常,包含完整的堆栈、请求上下文和调用链路,不需要手动订阅事件;异常信息在观测云控制台中聚合展示和告警。
常见问题(FAQ)
Q:.NET Core / .NET 5+ 还需要 AppDomain 事件吗?
A:仍然有效,但 ASP.NET Core 更推荐用中间件(ExceptionHandlerMiddleware)统一处理请求管道中的异常。
Q:async/await 中的异常能被 UnhandledException 捕获吗?
A:不能。异步 Task 中的异常由 TaskScheduler.UnobservedTaskException 处理,两者都需要订阅。
Q:记录完异常后程序会继续运行吗?
A:UnhandledException 触发时进程已经在终止过程中,你只能记录日志、不能做恢复操作。UnobservedTaskException 调用 SetObserved() 后可以阻止进程崩溃。