Как реализовать один обработчик исключений «catch'em all» с резюме? - PullRequest
30 голосов
/ 03 декабря 2008

Интересно, как мне написать catch'em all обработчик исключений на уровне приложения, который даст пользователю возможность возобновить поток приложения?

Ответы [ 9 ]

33 голосов
/ 03 декабря 2008

Если вы работаете с приложением Windows Forms: добавьте обработчик к событию Application.ThreadException.

32 голосов
/ 03 декабря 2008

Я предполагаю, что вы пишете приложение для Windows, и в этом случае да , вы можете сделать это. Я оставлю права и недостатки того, стоит ли вам это делать другим. На этот счет уже есть достаточно ответов, и я предлагаю вам внимательно их рассмотреть, прежде чем вы действительно сделаете это .

Обратите внимание, что этот код будет вести себя в отладчике иначе, чем при непосредственном запуске приложения (возможно, еще одна причина этого не делать). Чтобы приложение показывало окно сообщения и затем продолжало работу, вам нужно будет запустить приложение из проводника, а не из Visual Studio.

Создайте новое приложение для форм Windows. Код в Program.cs выглядит примерно так:

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);
        }
    }
}

Затем код в Form1 будет выглядеть примерно так:

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");
        }

    }
}

(добавить button1 к форме и прикрепить ее button1_Click.)

19 голосов
/ 03 декабря 2008

Это зависит от того, что вы подразумеваете под «резюме». Проблема с исключениями заключается в том, что, если вы не будете очень осторожны, к тому времени, когда произойдет исключение, состояние вашего приложения может быть повреждено - возможно, вы завершили половину операцию.

Если вы можете изолировать свои операции - так же, как база данных изолирует транзакции - тогда вы можете эффективно позволить своему пользователю возобновить работу с «последней точки фиксации». Это будет очень сильно зависеть от типа вашего приложения. Не могли бы вы дать нам более подробную информацию о том, какое приложение вы создаете?

6 голосов
/ 15 мая 2012

Используйте приведенный ниже код в своем классе program.cs. Он будет автоматически отправлять почту при возникновении исключения.

using System;
using System.Windows.Forms;
using System.Net;
using System.Net.Mail;
using System.Threading; 

namespace ExceptionHandlerTest
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.ThreadException +=
                new ThreadExceptionEventHandler(Application_ThreadException);

            // Your designer generated commands.
        }

        static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) 
        {

            var fromAddress = new MailAddress("your Gmail address", "Your name");
            var toAddress = new MailAddress("email address where you want to receive reports", "Your name");
            const string fromPassword = "your password";
            const string subject = "exception report";
            Exception exception = e.Exception;
            string body = exception.Message + "\n" + exception.Data + "\n" + exception.StackTrace + "\n" + exception.Source;

            var smtp = new SmtpClient
            {
                Host = "smtp.gmail.com",
                Port = 587,
                EnableSsl = true,
                DeliveryMethod = SmtpDeliveryMethod.Network,
                UseDefaultCredentials = false,
                Credentials = new NetworkCredential(fromAddress.Address, fromPassword)
            };
            using (var message = new MailMessage(fromAddress, toAddress)
            {
                Subject = subject,
                Body = body
            })
            {
                //You can also use SendAsync method instead of Send so your application begin invoking instead of waiting for send mail to complete. SendAsync(MailMessage, Object) :- Sends the specified e-mail message to an SMTP server for delivery. This method does not block the calling thread and allows the caller to pass an object to the method that is invoked when the operation completes. 
                smtp.Send(message);
            }
        }
    }
}
4 голосов
/ 03 декабря 2008

Я не думаю, что это действительно возможно, используя глобальный обработчик ошибок. Вам необходимо выяснить, какие ошибки можно исправить в разных точках вашего приложения, и написать конкретные обработчики ошибок для устранения ошибок по мере их возникновения - если только вы не захотите прибегнуть к перезапуску приложения, которое может или не может работать в зависимости от того, что Фактическая ошибка Чтобы выполнить любое резюме, вам нужно сохранить достаточно состояния, чтобы перезапустить из известного исправного состояния.

0 голосов
/ 03 декабря 2008

Вы должны прочитать обо всех проблемах, связанных со стилем обработки ошибок в VB "On Error Resume Next". Похоже, вы пытаетесь реализовать это для C #.

Даже если вы можете продолжить с того места, где сгенерировано исключение, это неправильный метод обработки ошибок. Глобальный обработчик не может реально обработать любую ошибку / исключение - он не может знать, что требуется для любой произвольной ситуации.

Вы должны были бы установить какую-то глобальную переменную, и чтобы основной код постоянно проверял ее на наличие ошибок (т. Е. Использовать технику VB).

Я думаю, что лучшее, что вы можете сделать для восстановления после описанной ошибки, - это перехватить исключение на уровне приложения, зарегистрировать проблему, проинформировать пользователя (и, возможно, сгенерировать / отправить какой-либо отчет о проблеме для вас). ) и перезапустите приложение. Конечно, если вы поймаете исключение ближе к проблемной области, у этого обработчика есть шанс сделать что-то более интеллектуальное, поэтому вам не следует полагаться на обработчик уровня приложения в качестве опоры - просто как на отказоустойчивый.

0 голосов
/ 03 декабря 2008

В некоторых версиях .NET вы можете поместить ловушку вокруг Application.Run () (вы найдете это в program.cs), и это должно отлавливать все исключения основного потока, однако в большинстве случаев это может быть плохой дизайн и не даст вам много возможностей «возобновить». Кроме того, вам всегда придется вручную обрабатывать любые исключения в фоновых потоках.

Вы можете создать приложение, которое будет "ловить все" и отображать общее сообщение об ошибке и информацию об отладке. Это нормально, если вы выходите после этого. Что крайне обескураживает, так это предоставление «резюме» пользователю, так как это, вероятно, даст вам больше проблем в долгосрочной перспективе.

0 голосов
/ 03 декабря 2008

Блок приложения Microsoft Enterprise Library для обработки исключений содержит примеры того, как вы можете это сделать.

По сути, вы окружаете код, который может генерировать исключения, следующим образом:

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

Затем вы можете настроить Политику так, чтобы она показывала пользователю диалог и спрашивала, хочет ли он продолжить.

Вам все еще нужно поместить блоки try catch в ваш код в тех точках, где, по вашему мнению, вы находитесь в согласованном состоянии.

0 голосов
/ 03 декабря 2008

Это просто кричит о плохом дизайне. Никогда не используйте исключения для таких вещей. Исключения должны использоваться ТОЛЬКО в тех случаях, когда программист не собирался это делать.

Если вы хотите обработку ошибок. Не используйте подобные исключения, скорее создайте систему, в которой вы сохраняете состояния и можете вернуться к состояниям и т. д., но используя исключения для обработки состояний, плохая идея.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...