如何更有效的处理系统异常

来源:互联网 发布:linux的copy命令 编辑:程序博客网 时间:2024/06/09 14:47

一、             问题

对于系统异常,不管是开发(维护)人员还是用户,大家的直观感觉是:系统存在问题。但是对于开发人员,系统异常对话框往往能给出我们异常的类型以及异常发生的地方,所以我们看到异常后,就方便进一步去查找错误,并进行修正。但是,当用户遇到一个系统异常时,心中就充满了厌恶,他从异常中并不能找到处理异常的方法,唯一的方法是把异常发给开发人员进行分析(如果这也算好处的话)。但若在客户现场发生了系统异常,我们应该通过日志来记录,并通过对话框提示用户如何应对(或重启系统、或联系维护人员)。所以,我们应该尽量避免系统在客户现场弹出系统异常。

二、             解决方案

不管什么系统,完全没有bug,没有漏洞是不可能的,关键是应对这些问题的策略。现在微软的系统,若是发生了系统异常,它会弹出一个对话框,提示用户是否把异常发给微软处理,当然其中也有重启系统、恢复数据的提示操作。那么我们的系统呢?对于能够预测得到的异常,能够捕捉的异常,当然,我们也要给用户提示解决方案(或重启,或验证数据合法性及操作流程正确性),对于一些我们不能预测的异常,也要给出相应解决方案,例如:若网络问题、配置问题,或服务器重启等,应提醒用户检查或联系管理员处理,若是无法确认的问题,可以联系系统维护人员处理等。这样,用户在使用我们的系统时,才有更强的安全感。

三、             具体方法

那么如何才能避免弹出系统异常并给出处理方法呢?首先,要尽量捕获系统所有异常,然后对系统进行分类处理。

1)        捕获异常:

对于可以预测的异常,我们在系统的相应位置都会进行捕获并处理,例如:在业务逻辑层进行业务逻辑检查时,发现逻辑不正确,然后就会抛出CheckException异常,然后在客户端的相应位置进行捕获,并弹出对话框,提示用户出现了什么问题,应如何正确解决等;对于权限处理的,我们也会弹出SecurityException异常;对于网络问题,我们会弹出RemotingException异常,对于服务器不可用的问题,我们会弹出ServerExceiption异常或SocketException异常。但是还有些异常是我们无法预知的,这时应如何处理呢?难道处处捕获Exception吗?这是不够现实的,可喜的是,.net Framework中已经给我们提供了相应的处理方法。

对于异常的处理,你已经会想到:对于UI所在的主线程中的异常,我们可以捕获异常,并弹出提示,但若是其它线程中的异常应该如何处理呢?这些问题,.net Framework设计人员也想到了,针对这两种异常的处理办法分别是:通过Application.ThreadException事件捕获UI主线程异常,并进行相应处理;通过AppDomain.CurrentDomain.UnhandledException事件捕获其它异常,但是此事件只能探测到非UI线程异常,却不能阻止系统异常的弹出,所以可以在此处以日志的形式记录系统异常。

/// <summary>

    /// 程序入口类

    /// </summary>

    static class Program

    {

        [STAThread]

        [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]

        public static void Main(string[] args)

        {

            // 添加一个线程事件处理器来处理UI线程相关异常

            Application.ThreadException += new ThreadExceptionEventHandler(Form1_UIThreadException);

 

            // 始终将异常传送到ThreadException 处理程序。忽略应用程序配置文件。

            Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

 

            // 添加一个事件处理器来处理非UI线程异常.

            AppDomain.CurrentDomain.UnhandledException +=

                new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

 

            // 运行程序.

            Application.Run(new Form1());

        }

 

 

        // 通过弹出对话框处理UI线程异常,并询问用户是否终止程序继续运行.

        private static void Form1_UIThreadException(object sender, ThreadExceptionEventArgs t)

        {

            DialogResult result = DialogResult.Cancel;

            try

            {

                result = ShowThreadExceptionDialog("Windows Forms Error", t.Exception);

            }

            catch

            {

                try

                {

                    MessageBox.Show("Fatal Windows Forms Error",

                        "Fatal Windows Forms Error", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Stop);

                }

                finally

                {

                    Application.Exit();

                }

            }

 

            // Exits the program when the user clicks Abort.

            if (result == DialogResult.Abort)

                Application.Exit();

        }

 

        // 通过弹出对话框处理非UI线程异常,并询问用户是否终止程序继续运行.

        // 注意:这类异常不能终止异常,所以它仅能以日志的形式记录下来,并通知用户。

        private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)

        {

            try

            {

                Exception ex = (Exception)e.ExceptionObject;

                string errorMsg = "An application error occurred. Please contact the adminstrator " +

                    "with the following information:/n/n";

 

                // Since we can't prevent the app from terminating, log this to the event log.

                if (!EventLog.SourceExists("ThreadException"))

                {

                    EventLog.CreateEventSource("ThreadException", "Application");

                }

 

                // Create an EventLog instance and assign its source.

                EventLog myLog = new EventLog();

                myLog.Source = "ThreadException";

                myLog.WriteEntry(errorMsg + ex.Message + "/n/nStack Trace:/n" + ex.StackTrace);

            }

            catch (Exception exc)

            {

                try

                {

                    MessageBox.Show("Fatal Non-UI Error",

                        "Fatal Non-UI Error. Could not write the error to the event log. Reason: "

                        + exc.Message, MessageBoxButtons.OK, MessageBoxIcon.Stop);

                }

                finally

                {

                    Application.Exit();

                }

            }

        }

 

        // 创建异常处理信息,并以对话框的形式通知用户。

        private static DialogResult ShowThreadExceptionDialog(string title, Exception e)

        {

            string errorMsg = "An application error occurred. Please contact the adminstrator " +

                "with the following information:/n/n";

            errorMsg = errorMsg + e.Message + "/n/nStack Trace:/n" + e.StackTrace;

            return MessageBox.Show(errorMsg, title, MessageBoxButtons.AbortRetryIgnore,

                MessageBoxIcon.Stop);

        }

 

    }

 

/// <summary>

    /// 主窗口类

    /// </summary>

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

        // 当点击时,弹出UI线程异常

        private void kdButton1_Click(object sender, EventArgs e)

        {

            throw new ArgumentException("The parameter was invalid");

        }

        // 新建一个线程,使之独立于Windows窗口,并抛出异常.

        private void kdButton2_Click(object sender, EventArgs e)

        {

            ThreadStart newThreadStart = new ThreadStart(newThread_Execute);

            Thread newThread = new Thread(newThreadStart);

            newThread.Start();

        }

 

        // 对立线程抛出的非UI异常.

        void newThread_Execute()

        {

            throw new Exception("The method or operation is not implemented.");

        }

 

    }

2)        异常分类处理

对于异常的分类处理,就需要我们对异常进行分类了。这需要我们针对不同的异常定义不通的异常类型,并在适当的地方抛出,当然这些异常都是可预知的,我们在代码中可以捕获并处理。但是,对于一些我们不可预知的类应该如何处理呢?这个不用担心,.net Framework已经定义了许多异常类型,足够我们使用的,只要我们正确分别处理就好了,比如:有些类型的异常是系统配置错误,我们可以提示解决办法,或直接让用户联系管理员,对于一些系统漏洞(真正的不可预知),可以提示用户联系维护人员,或像微软那样让用户直接把异常信息发给维护部门。

四、             总结

为了解决系统异常,我们花费了许多时间,但系统异常是不可避免的。所以我们不可能解决所有系统异常,但是我们可以使系统异常以更加友好的方式弹出,我们可以对不同类型的系统异常,给出用户建议性的解决办法。用户在遇到系统异常时,不再会有烦躁不安的心情,不再有抱怨的态度,不再有无所适从的举措,有的只是安全,放心,稳妥的感觉,并及时地以正确的方式进行处理。

原创粉丝点击