How to implement one “catch'em all” exception handler with resume?

前端 未结 9 601
梦如初夏
梦如初夏 2020-11-29 07:07

I wonder how can I write a catch\'em all exception handler in the application level which will give the user the option to resume the application f

相关标签:
9条回答
  • 2020-11-29 07:39

    I don't think this is really feasible using a global error handler. You need to figure out what kind of errors are recoverable at different points in your application and write specific error handlers to address the errors as they occur -- unless you want to resort to application restart, which may or may not work depending on what the actual error is. In order to do any kind of resume, you'll need to save enough state to restart from a known good state.

    0 讨论(0)
  • 2020-11-29 07:44

    I assume you are writing a Windows application in which case, yes, you can do this. I will leave the rights and wrongs of whether or not you should to others. There are already enough answers which look at this and I suggest you consider them carefully before you actually do this.

    Note, that this code will behave differently in the debugger than it does if you run the application directly (another reason not to do it perhaps). To get the application to show the messagebox and to continue on thereafter you will need to run the application from explorer, not from visual studio.

    Create a new Windows forms application. The code in Program.cs looks something like this:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Windows.Forms;
    
    namespace WindowsFormsApplication2 {
        static class Program {
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main() {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Form1 form1 = new Form1();
                Application.ThreadException += new ThreadExceptionEventHandler(form1.UnhandledThreadExceptionHandler);
                Application.Run(form1);
            }
        }
    }
    

    Then make the code in Form1 look something like this:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Windows.Forms;
    
    namespace WindowsFormsApplication2 {
        public partial class Form1 : Form {
            public Form1() {
                InitializeComponent();
            }
    
            public void UnhandledThreadExceptionHandler(object sender, ThreadExceptionEventArgs e) {
                this.HandleUnhandledException(e.Exception);
            }
    
            public void HandleUnhandledException(Exception e) {
                // do what you want here.
                if (MessageBox.Show("An unexpected error has occurred. Continue?",
                    "My application", MessageBoxButtons.YesNo, MessageBoxIcon.Stop,
                    MessageBoxDefaultButton.Button2) == DialogResult.No) {
                    Application.Exit();
                }
            }
    
            private void button1_Click(object sender, EventArgs e) {
                throw new ApplicationException("Exception");
            }
    
        }
    }
    

    (Add button1 to the form and attach it button1_Click.)

    0 讨论(0)
  • 2020-11-29 07:44

    It depends on what you mean by "resume". The trouble with exceptions is that unless you're very careful, by the time an exception happens your application state is quite possibly corrupt - you might have completed half an operation.

    If you can isolate your operations - much like a database isolates transactions - then you can effectively let your user resume from the "last commit point". That will very much depend on the type of your application though. Could you give us more details about the kind of application you're building?

    0 讨论(0)
  • 2020-11-29 07:45

    In some versions of .NET you can actually put a catcher around the Application.Run() (you'll find this in program.cs) and this should catch all the Main Thread's exceptions however in most cases this maybe poor design and wont give you much of an opportunity to "resume". Additionally you will always have to manually handle any exceptions on background threads.

    You can design an app to "catch all" and display a common error message and debug info, this is fine as long as you exit afterwards. What is highly discouraged is making a "resume" available to the user as this will probably give you more problems in the long-run.

    0 讨论(0)
  • 2020-11-29 07:46

    You should read up on all the problems associated with VB's "On Error Resume Next" style of error handling. It sounds like you're trying to implement this for C#.

    Even if you can resume from the point of where the exception is generated, this is a broken technique for error handling. There's no way for a global handler to actually be able to handle any error/exception - it can't possibly know what's required for any arbitrary situation.

    You would have to set some sort of global variable, and have the mainline code continually check it for error indications (ie., use the VB technique).

    I think the best you can do to recover from an error like you're describing is to catch the exception at the application level, log the problem, inform the user (and potentially generate/send some sort of problem report for you), and restart the application. Of course, if you catch the exception closer to the problem area, that handler has a chance to do something a bit more intelligent, so you should not rely on the app-level handler as a crutch - just as a fail-safe.

    0 讨论(0)
  • 2020-11-29 07:51

    Microsoft Enterprise Library Exception Handling Application Block has examples of how you can do this.

    Basically you surround the code that can throw exceptions with this:

    try
    {
      MyMethodThatMightThrow();
    }
    catch(Exception ex)
    {
       bool rethrow = ExceptionPolicy.HandleException(ex, "SomePolicy");
       if (rethrow) throw;
    }
    

    Then you can configure the Policy to show a dialog to the user and ask if she wants to continue.

    You still need to put try catch blocks around in your code at points where you believe you are at a consistent state.

    0 讨论(0)
提交回复
热议问题