WinForms Глобальная обработка исключений?

Я реализовал программное обеспечение, имеющее библиотеку DLL, которая содержит огромный набор классов, который включает в себя все методы для моего программного обеспечения.

Теперь я хочу иметь возможность обрабатывать некоторые глобальные ошибки, такие как ошибка # 26, которая не является связанной с сетью ошибкой для всех этих классов, вместо того, чтобы идти в каждый класс и добавлять ее. Как это сделать?

Ответы

Ответ 1

Если #26 является исключением, вы можете использовать событие AppDomain.CurrentDomain.UnhandledException. Если это просто возвращаемое значение, то я не вижу никакой возможности справиться с этим глобально.

Ответ 2

С его приложением winforms вы можете просто заключить Application.Run(new MainForm()); в блок catch try.

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, и вы должны прочитать разницу между ними здесь, на MSDN.

Из MSDN:

Для некоторых моделей приложений событие UnhandledException может быть вытеснено другими событиями, если необработанное исключение встречается в основном потоке приложения.

В приложениях, использующих Windows Forms, необработанные исключения в основном потоке приложения вызывают событие Application.ThreadException. Если это событие обрабатывается, поведение по умолчанию заключается в том, что необработанное исключение не завершает приложение, хотя приложение остается в неизвестном состоянии. В этом случае событие UnhandledException не создается. Это поведение можно изменить с помощью файла конфигурации приложения или с помощью метода Application.SetUnhandledExceptionMode, чтобы изменить режим на UnhandledExceptionMode.ThrowException до того, как обработчик события ThreadException подключен. Это относится только к основной теме приложения. Событие UnhandledException создается для необработанных исключений, созданных в других потоках.

Ответ 3

С ссылкой Централизованная обработка исключений в приложении С# 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);
    }
}  

В вышеприведенном классе мы присоединим обработчик событий к двум событиям. Лучше присоединить эти события, как только начнется основной метод.

Application.ThreadException. Это событие будет поднято, если исключение будет передано в основном потоке. Если мы добавим обработчик событий, то исключение обрабатывается по методу.

AppDomain.CurrentDomain.UnhandledException. Это событие будет поднято, когда исключение будет добавлено в дополнительные потоки, используемые в приложении. Хуже сценарий здесь, как только выполнение обработчиков заканчивается, исключение снова бросается, тогда как приложение заканчивается. Это необходимо обработать. Здесь я использовал немного кода для обработки этой ситуации и продолжения выполнения приложения без перерыва.

Логика, которую я использовал для преодоления этой ситуации, - это просто приостановить поток в обработчике событий, чтобы приложение продолжало работать нормально. Снова возникает проблема приостановки этого потока. Когда основная форма закрыта, приложение обычно должно выйти, но по мере того, как поток находится в состоянии приостановления, приложение все равно будет работать. Таким образом, чтобы полностью завершить приложение и остановить процесс, необходимо вызывать Environment.Exit(-1) до окончания основного метода.

Ответ 4

Во-первых, вы должны добавить:

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

После этого вы можете перехватывать исключения, например:

[STAThread]
    static void Main()
    {

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

        if (DataBaseMNG.Init())
        {
            Application.Run(new MainForm());
        }
    }

    /// <summary>
    /// Global exceptions in Non User Interfarce(other thread) antipicated error
    /// </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 Interfarce antipicated error
    /// </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");
    }

Ответ 6

Глобальный перехват ошибок в 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
    }
}

Ответ 7

Как продолжение того, что показано выше, я использую следующее:

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().