網上找到兩個方式,一個簡單的只是做個記錄,另一個能像QQ一樣提交到后台。
方法一:

static class Program { /// <summary> /// 應用程序的主入口點。 /// </summary> [STAThread] static void Main() { try { //設置應用程序處理異常方式:ThreadException處理 Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); //處理UI線程異常 Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); //處理非UI線程異常 AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); #region 應用程序的主入口點 Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); #endregion } catch (Exception ex) { string str = GetExceptionMsg(ex,string.Empty); MessageBox.Show(str, "系統錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error); } } static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) { string str = GetExceptionMsg(e.Exception, e.ToString()); MessageBox.Show(str, "系統錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error); //LogManager.WriteLog(str); } static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { string str = GetExceptionMsg(e.ExceptionObject as Exception, e.ToString()); MessageBox.Show(str, "系統錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error); //LogManager.WriteLog(str); } /// <summary> /// 生成自定義異常消息 /// </summary> /// <param name="ex">異常對象</param> /// <param name="backStr">備用異常消息:當ex為null時有效</param> /// <returns>異常字符串文本</returns> static string GetExceptionMsg(Exception ex,string backStr) { StringBuilder sb = new StringBuilder(); sb.AppendLine("****************************異常文本****************************"); sb.AppendLine("【出現時間】:" + DateTime.Now.ToString()); if (ex != null) { sb.AppendLine("【異常類型】:" + ex.GetType().Name); sb.AppendLine("【異常信息】:" + ex.Message); sb.AppendLine("【堆棧調用】:" + ex.StackTrace); } else { sb.AppendLine("【未處理異常】:" + backStr); } sb.AppendLine("***************************************************************"); return sb.ToString(); } }
方法二:
轉載於:王旭博客 » C# 全局異常處理。
1.本文目標
我們准備做一個程序,具備全局的異常捕獲及處理能力,類似大多數知名程序那樣彈個窗口,發送錯誤報告,友好的提示。類似騰訊QQ異常,Firefox異常等異常窗口來進行錯誤報送,如下圖所示:
2.C#異常處理機制簡介
C#也跟其他的OOP語言一樣能夠處理可預見的異常信息,如網絡連接失敗,文件讀取失敗,數組越界等異常。當你的程序遇到了異常的時候CLR會拋出一個異常給你,這樣你就得到了一個處理異常的機會,這個異常會一層一層的返回給調用者,最后返回到Main方法的起始點中,但是如果你沒有進行處理的話最終會被CLR處理,它將終止程序。
3. C#全局異常捕獲處理
目前為止,很多的程序都是以感覺哪段代碼可能異常就把它try起來然后彈個Message的方式進行提示,好一點處理的還會記錄日志信息來解決。如果純粹看簡單的錯誤提示其實是很難找到錯誤的,尤其是程序越來越大的時候,甚至有時候你都不知道這個錯誤是哪個模塊出現的,是怎么出現的,點擊哪個按鈕出現的!是不是得去問客戶?在我看來極大多數情況是完全沒有必要的,我們完全有能力捕獲完整的異常。
好了,廢話解釋完畢,開始構建我們的具備異常處理捕獲及處理能力的程序吧!這里以Winform舉例,其他的都差不多,如WPF什么的都是可以捕獲全局異常的。
3.1 構建Bug處理模塊
首先我建了個Winform項目命名為 WinformException
用於處理Bug,為了利於以后項目復用 這個項目是單獨用於處理Bug的,在該項目中構建了如下窗體。
這個用於對Bug報送的處理,對客戶的錯誤解釋界面,你可以根據自己的業務需求進行更改,總而言之把錯誤完整的保存下來即可。
出現錯誤不可怕,可怕的是出了錯 你卻不知道。
窗口的代碼如下:

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace WinformException { public partial class FrmBugReport : Form { #region 全局變量 Exception _bugInfo; #endregion #region 構造函數 /// <summary> /// Bug發送窗口 /// </summary> /// <param name="bugInfo">Bug信息</param> public FrmBugReport(Exception bugInfo) { InitializeComponent(); _bugInfo = bugInfo; this.txtBugInfo.Text = bugInfo.Message; lblErrorCode.Text = Guid.NewGuid().ToString(); } /// <summary> /// Bug發送窗口 /// </summary> /// <param name="bugInfo">Bug信息</param> /// <param name="errorCode">錯誤號</param> public FrmBugReport(Exception bugInfo, string errorCode) { InitializeComponent(); _bugInfo = bugInfo; this.txtBugInfo.Text = bugInfo.Message; lblErrorCode.Text = errorCode; } #endregion #region 公開靜態方法 /// <summary> /// 提示Bug /// </summary> /// <param name="bugInfo">Bug信息</param> /// <param name="errorCode">錯誤號</param> public static void ShowBug(Exception bugInfo, string errorCode) { new FrmBugReport(bugInfo, errorCode).ShowDialog(); } /// <summary> /// 提示Bug /// </summary> /// <param name="bugInfo">Bug信息</param> public static void ShowBug(Exception bugInfo) { ShowBug(bugInfo, Guid.NewGuid().ToString()); } #endregion private void btnDetailsInfo_Click(object sender, EventArgs e) { MessageBox.Show("異常詳細信息:" + _bugInfo.Message + "\r\n跟蹤:" + _bugInfo.StackTrace); } } }
這個項目就完成了。
3.2 構建異常測試程序
接下來構建我們的測試程序,以及如何捕捉代碼。我在解決方案中再建了一個Winform項目命名為WinformTest
做測試,如下圖所示:
先來看看我們在
Program.cs
中做了什么手腳吧,這個就是全局捕捉異常的核心代碼,Program.cs
代碼如下:
using System; using System.Collections.Generic; using System.Windows.Forms; namespace WinformTest { static class Program { /// <summary> /// 應用程序的主入口點。 /// </summary> [STAThread] static void Main() { //全局異常捕捉 Application.ThreadException += Application_ThreadException; //UI線程異常 AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; //多線程異常 Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new FrmMain()); } //UI線程異常 static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) { WinformException.FrmBugReport.ShowBug(e.Exception); } //多線程異常 static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { WinformException.FrmBugReport.ShowBug((Exception)e.ExceptionObject); } } }
第一行我注冊了UI線程異常處理事件
- Application.ThreadException += Application_ThreadException; //UI線程異常
這個用於捕獲主線程的錯誤,也就是UI,大多數異常都會聚集在此,我們在該事件中處理了異常,程序則不會強制退出。
然后第二行注冊了其他多線程異常處理事件(除UI之外的線程)
- AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; //多線程異常
這個用於捕獲主線程之外的所有線程的異常,但是無法讓程序不被強制退出,當在這里面的代碼執行完畢后程序依然會退出!不過幸運的是我們有其他的辦法來解決。
然后看看測試窗體 FrmMain.cs
的代碼如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Threading; using System.Windows.Forms; namespace WinformTest { public partial class FrmMain : Form { public FrmMain() { InitializeComponent(); } //普通異常測試 private void btnTest1_Click(object sender, EventArgs e) { throw new Exception("啊..我這行代碼異常了..."); } //多線程異常測試 private void btnTest2_Click(object sender, EventArgs e) { Thread th = new Thread(() => { throw new Exception("啊哦,異常錯誤。"); }); th.IsBackground = true; th.Start(); } } }
其實就是兩個簡單的測試而已,點擊按鈕會彈出如下界面。
我們可以在確定按鈕中編寫發送到數據庫,或者是把bug詳細信息存放到txt中。拿到了Exception
,由你任意處置吧,我這里把Exception
的StackTrace
屬性展示到了錯誤詳細信息按鈕上,不會看StackTrace
的,該反省下了。耐心看下就明白了,是很簡單的,它對Bug是如何出現的步驟表示的非常清楚。
好了到此為止,Bug處理也就OK了,還算非常簡單的,只是可能我長篇大論了。哈..下次盡量簡短..現在應該掌握了對異常的合理處理了吧。
該解決方案的源碼下載:WinformException
小知識:如何處理多線程中的異常,讓程序不會強制退出。
你可以這樣,把多線程中的任務全部try起來。

Thread t = new Thread((ThreadStart)delegate { try { throw new Exception("多線程異常"); } catch (Exception error) { MessageBox.Show("線程異常:" + error.Message + Environment.NewLine + error.StackTrace); } }); t.Start();
你還可以這樣,把異常拋回主線程,這個比較推薦。

Thread t = new Thread((ThreadStart)delegate { try { throw new Exception("非窗體線程異常"); } catch (Exception ex) { this.BeginInvoke((Action)delegate { throw ex; }); } }); t.Start();