即使全代碼覆蓋 try-catch,仍有兩類異常無法攔截:
Finalize 方法中拋出的異常,或內存耗盡導致的 GC 失敗AppDomain.CurrentDomain.UnhandledException += (sender, e) => {
Exception ex = (Exception)e.ExceptionObject;
bool isTerminating = e.IsTerminating; // .NET 2.0+ 恆為 true
// 關鍵動作:日誌記錄、數據備份、告警通知
Log.Fatal("未捕獲異常", ex);
BackupCriticalData();
AlertOpsTeam(ex);
};
// Program.cs 入口點
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Application.ThreadException += (s, e) => HandleUIThreadException(e.Exception);
AppDomain.CurrentDomain.UnhandledException += (s, e) => HandleNonUIThreadException(e.ExceptionObject as Exception);
關鍵點:UI 線程異常可選擇不終止進程(UnhandledExceptionMode.CatchException),非 UI 線程異常必須記錄並優雅退出。
<!-- Web.config -->
<system.web>
<customErrors mode="On" defaultRedirect="/Error.html">
<error statusCode="500" redirect="/500.html" />
</customErrors>
</system.web>
// Global.asax
protected void Application_Error() {
var ex = Server.GetLastError();
Log.Error("Web未捕獲異常", ex);
// 發送郵件、寫入事件日誌等
Server.ClearError();
Response.Redirect("/Error.html");
}
// 必須訂閱,否則靜默失敗無感知
AppDomain.CurrentDomain.UnhandledException += (s, e) => {
var ex = e.ExceptionObject as Exception;
Log.Fatal("服務崩潰", ex);
// 嘗試重啟邏輯或通知監控系統
Environment.Exit(1); // 非零退出碼觸發服務管理器重啟
};
try-catch 中處理可預期異常