WinForms全局异常处理?

i1icjdpr  于 2022-11-17  发布在  其他
关注(0)|答案(7)|浏览(134)

我已经实现了一个软件,它有一个DLL库,其中包含一组类,其中包括我的软件的所有方法。
现在我希望能够处理一些全局错误,如错误#26,这是一个没有网络相关的错误,所有这些类,而不是去每个类,并添加它。我应该怎么做?

omvjsjqw

omvjsjqw1#

如果#26是一个异常,那么你可以使用AppDomain.CurrentDomain.UnhandledException事件。如果它只是一个返回值,那么我看不出有任何机会全局处理它。

public static void Main()
{
    AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);

    // start main thread here
}

static void MyHandler(object sender, UnhandledExceptionEventArgs args) 
{
    Exception e = (Exception) args.ExceptionObject;
    Console.WriteLine("MyHandler caught : " + e.Message);
}
jxct1oxe

jxct1oxe2#

由于它是一个winforms应用程序,您可以将Application.Run(new MainForm());包含在一个try catch块中。

static void Main()
{
try {
 Application.Run(new MainForm());
} catch(SystemException)//just as an example 
{
 //log or handle the error here. 
}
}

我不知道这种解决方案会引起什么影响,但我只是告诉你你需要什么。
其他选项是订阅Application.ThreadException事件。
点击此处阅读更多信息:unhandledexceptions
还有AppDomain.UnhandledException,您应该阅读它们之间的差异here on MSDN
来自MSDN:

  • 对于某些应用程序模型,如果未处理的异常发生在主应用程序线程中,UnhandledException事件可能会被其他事件抢占。*
  • 在使用Windows窗体的应用程序中,主应用程序线程中未处理的异常会引发Application.ThreadException事件。如果处理此事件,则默认行为是未处理的异常不会终止应用程序,尽管应用程序仍处于未知状态。在这种情况下,不会引发UnhandledException事件。可以使用应用程序配置文件更改此行为。或者使用Application.SetUnhandledExceptionMode方法将模式更改为UnhandledExceptionMode.ThrowException,然后再挂接ThreadException事件处理程序。这仅适用于主应用程序线程。对于在其他线程中引发的未处理异常,会引发UnhandledException事件。*
sgtfey8w

sgtfey8w3#

通过参考Centralized Exception Handling在C# Windows中的应用,我找到了一个很好的解决方案:

static class Program
{
    [STAThread]
    static void Main()
    {
        // Add handler to handle the exception raised by main threads
        Application.ThreadException += 
        new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);

        // Add handler to handle the exception raised by additional threads
        AppDomain.CurrentDomain.UnhandledException += 
        new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());

        // Stop the application and all the threads in suspended state.
        Environment.Exit(-1);            
    }

    static void Application_ThreadException
        (object sender, System.Threading.ThreadExceptionEventArgs e)
    {// All exceptions thrown by the main thread are handled over this method

        ShowExceptionDetails(e.Exception);
    }

    static void CurrentDomain_UnhandledException
        (object sender, UnhandledExceptionEventArgs e)
    {// All exceptions thrown by additional threads are handled in this method

        ShowExceptionDetails(e.ExceptionObject as Exception);

        // Suspend the current thread for now to stop the exception from throwing.
        Thread.CurrentThread.Suspend();
    }

    static void ShowExceptionDetails(Exception Ex)
    {
        // Do logging of exception details
        MessageBox.Show(Ex.Message, Ex.TargetSite.ToString(), 
                MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

在上面的类中,我们将把一个事件处理程序附加到两个事件上。最好是在main方法一开始就附加这些事件。

Application.ThreadException-当在主线程中抛出异常时将引发此事件。如果添加事件处理程序,则通过方法处理异常。
AppDomain.CurrentDomain.UnhandledException-当应用程序中使用的其他线程抛出异常时,将引发此事件。更糟糕的情况是,一旦处理程序的执行结束,异常再次抛出,而应用程序结束。这需要处理。这里我使用了一些代码来处理这种情况,并继续执行应用程序而不中断。

我用来克服这种情况的逻辑是在事件处理程序中挂起线程,以便应用程序继续正常工作。挂起此线程时又出现了一个问题。当主窗体关闭时,应用程序通常需要退出,但由于线程处于挂起状态,应用程序仍将保持运行。因此,要完全退出应用程序并停止进程,必须在main方法结束之前调用Environment.Exit(-1)。

ig9co6j1

ig9co6j14#

首先,您应该添加:

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

之后,您可以捕获异常,例如:

[STAThread]
    static void Main()
    {

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
        Application.ThreadException += ApplicationThreadException;
        AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;

        Application.Run(new MainForm());
    }

    /// <summary>
    /// Global exceptions in Non User Interface (other thread) handler
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private static void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        var message =
            String.Format(
                "Sorry, something went wrong.\r\n" + "{0}\r\n" + "{1}\r\n" + "Please contact support.",
                ((Exception)e.ExceptionObject).Message, ((Exception)e.ExceptionObject).StackTrace);
        MessageBox.Show(message, @"Unexpected error");
    }

    /// <summary>
    /// Global exceptions in User Interface handler
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private static void ApplicationThreadException(object sender, ThreadExceptionEventArgs e)
    {
        var message =
            String.Format(
                "Sorry, something went wrong.\r\n" + "{0}\r\n" + "{1}\r\n" + "Please contact support.",
                e.Exception.Message, e.Exception.StackTrace);
        MessageBox.Show(message, @"Unexpected error");
    }
irlmq6kh

irlmq6kh6#

winforms中的全局错误拦截

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        try
        {
            Application.Run(new myForm());
        }
        catch (Exception ex)
        {
            HandleException(ex);
        }
    }

    internal static void HandleException(Exception ex)
    {
        string LF = Environment.NewLine + Environment.NewLine;
        string title = $"Oups... I got a crash at {DateTime.Now}";            
        string infos = $"Please take a screenshot of this message\n\r\n\r" +
                       $"Message : {LF}{ex.Message}{LF}" +
                       $"Source : {LF}{ex.Source}{LF}" +
                       $"Stack : {LF}{ex.StackTrace}{LF}" +
                       $"InnerException : {ex.InnerException}";

        MessageBox.Show(infos, title, MessageBoxButtons.OK, MessageBoxIcon.Error); // Do logging of exception details
    }
}
9wbgstp7

9wbgstp77#

作为上面所示内容的扩展,我使用以下内容:

try
{
    Application.Run(new FormMain());
}
catch (Exception ex)
{
    RoboReporterConstsAndUtils.HandleException(ex);
}

...其中HandleException()方法可以类似于:

internal static void HandleException(Exception ex)
{
    var exDetail = String.Format(ExceptionFormatString,
        ex.Message,
        Environment.NewLine,
        ex.Source,
        ex.StackTrace,
        ex.InnerException);

    ExceptionLoggingService.Instance.LogAndEmailExceptionData(string.Format("{0}: {1}: {2}",
        DateTime.Now.ToLongDateString(), GetVersionInfo(), exDetail));
}

另一种剥这只猫皮的方法是:

static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    AppDomain.CurrentDomain.UnhandledException += Unhandled;
    Application.Run(new FormMain());
}

static void Unhandled(object sender, UnhandledExceptionEventArgs exArgs)
{
    ExceptionLoggingService.Instance.LogAndEmailMessage(String.Format
        ("From application-wide exception handler: {0}", exArgs.ExceptionObject));
}

当然,您可以在Unhandled()方法中做任何您想做的事情。

相关问题