【第一篇筆記】C# 全局容錯,全局異常


網上找到兩個方式,一個簡單的只是做個記錄,另一個能像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();
        }
    }
View Code

 

方法二:

轉載於:王旭博客 » C# 全局異常處理。

1.本文目標

我們准備做一個程序,具備全局的異常捕獲及處理能力,類似大多數知名程序那樣彈個窗口,發送錯誤報告,友好的提示。類似騰訊QQ異常,Firefox異常等異常窗口來進行錯誤報送,如下圖所示:

exception1

2.C#異常處理機制簡介

C#也跟其他的OOP語言一樣能夠處理可預見的異常信息,如網絡連接失敗,文件讀取失敗,數組越界等異常。當你的程序遇到了異常的時候CLR會拋出一個異常給你,這樣你就得到了一個處理異常的機會,這個異常會一層一層的返回給調用者,最后返回到Main方法的起始點中,但是如果你沒有進行處理的話最終會被CLR處理,它將終止程序。

 

3. C#全局異常捕獲處理

目前為止,很多的程序都是以感覺哪段代碼可能異常就把它try起來然后彈個Message的方式進行提示,好一點處理的還會記錄日志信息來解決。如果純粹看簡單的錯誤提示其實是很難找到錯誤的,尤其是程序越來越大的時候,甚至有時候你都不知道這個錯誤是哪個模塊出現的,是怎么出現的,點擊哪個按鈕出現的!是不是得去問客戶?在我看來極大多數情況是完全沒有必要的,我們完全有能力捕獲完整的異常。
好了,廢話解釋完畢,開始構建我們的具備異常處理捕獲及處理能力的程序吧!這里以Winform舉例,其他的都差不多,如WPF什么的都是可以捕獲全局異常的

3.1 構建Bug處理模塊

首先我建了個Winform項目命名為 WinformException 用於處理Bug,為了利於以后項目復用 這個項目是單獨用於處理Bug的,在該項目中構建了如下窗體。

exception2

這個用於對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);
        }
 
    }
}
View Code

 

這個項目就完成了。

 

3.2 構建異常測試程序

接下來構建我們的測試程序,以及如何捕捉代碼。我在解決方案中再建了一個Winform項目命名為WinformTest做測試,如下圖所示:

exception3 先來看看我們在 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線程異常處理事件

  1.  Application.ThreadException += Application_ThreadException; //UI線程異常

這個用於捕獲主線程的錯誤,也就是UI,大多數異常都會聚集在此,我們在該事件中處理了異常,程序則不會強制退出。

 

然后第二行注冊了其他多線程異常處理事件(除UI之外的線程)

  1.  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();
        }
    }
}

 

其實就是兩個簡單的測試而已,點擊按鈕會彈出如下界面。

exception4

我們可以在確定按鈕中編寫發送到數據庫,或者是把bug詳細信息存放到txt中。拿到了Exception,由你任意處置吧,我這里把ExceptionStackTrace屬性展示到了錯誤詳細信息按鈕上,不會看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();
View Code

 

你還可以這樣,把異常拋回主線程,這個比較推薦。

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM