Отчеты об исключениях из приложения WPF

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

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

Не совсем уверен, как это реализовать, или если это правильный способ сделать это.

Сообщение об ошибке было бы простой задачей, но я понятия не имею, как перехватить вывод необработанного исключения или получить коды выхода (я предполагаю, что программа выдаст код выхода, отличный от 0, при сбое).

Было бы здорово подтолкнуть в правильном направлении.


person Steinthor.palsson    schedule 18.05.2011    source источник


Ответы (4)


Ваш лучший шанс внутри приложения. Есть два крючка:

  • AppDomain.UnhandledException – это универсальное решение.
  • Application.ThreadException — специфический для пользовательского интерфейса улов. -all для исключений, возникших в потоках форм

Правильное место для «всеобъемлющего» зависит от семантики вашего приложения, и трудно сказать, куда вы должны его поместить, не зная вашего приложения. Приложение также должно установить Application.SetUnhandledExceptionMode.

Наличие внешнего сторожевого таймера менее полезно, так как он не может дать никакой значимой информации о причине сбоя приложения. К тому времени, когда он обнаруживает «неожиданный» выход (откуда он знает, что это «неожиданный»?), уже слишком поздно собирать какую-либо полезную информацию. С помощью внутреннего обработчика вы можете собрать исключение и стек и отправить их в службу анализа, такую ​​как bugcollect.com, а затем теперь вы сможете лучше понять, что произошло, но также и как часто это происходит и какое развертывание затронуто (где это происходит ). Существуют и другие подобные службы, такие как exceptioneer.com или Отчеты об ошибках Windows (для этого требуется, чтобы ваш код был подписан сертификатом доверенного центра, таким как Verisign). Полагаться на службу для сбора инцидентов намного лучше, чем отправлять почту, вы не хотите проснуться и найти 2 000 писем об инцидентах в своем почтовом ящике и начать просеивать их, чтобы понять, что произошло.

И последний мир: не изобретайте велосипед: уже существует множество фреймворков для сбора и регистрации исключений, таких как log4net и elmah.

person Remus Rusanu    schedule 18.05.2011
comment
Перехватывает ли «всеобъемлющий» исключения во всех потоках, или я должен подписаться на него в каждом потоке? Я переосмыслил подход к электронной почте и, очевидно, что какая-то база данных была бы намного лучше. :) - person Steinthor.palsson; 18.05.2011
comment
Для приложения WPF Application.ThreadException не существует. Вместо этого вам нужно обработать DispatcherUnhandledException. - person O'Rooney; 28.06.2013

Для этого вы можете использовать библиотеку NBug (также вы можете использовать пакет nuget здесь для простой установки). Просто установите пакет NuGet и настройте его, как показано ниже:

NBug.Settings.Destination1 =
  "Type=Mail;[email protected];[email protected];SmtpServer=smtp.mycompany.com;";
AppDomain.CurrentDomain.UnhandledException += NBug.Handler.UnhandledException;
Application.Current.DispatcherUnhandledException += NBug.Handler.DispatcherUnhandledException;

Теперь все необработанные исключения будут аккуратно перехвачены и упакованы для вас, и вы получите полную информацию об исключении по электронной почте. Используйте инструмент конфигуратора, чтобы убедиться, что ваша конфигурация верна.

person Teoman Soygul    schedule 18.05.2011

Ответы, связанные с событием AppDomain.UnhandledException, вероятно, делают неявное предполагается, что любое необработанное исключение возникает в потоке пользовательского интерфейса WPF. Это означает, что хотя они часто работают, формально они небезопасны для использования с операциями в других потоках. Более надежным вариантом является Application.DispatcherUnhandledException, который WPF позволяет приложениям реализовывать настраиваемые отчеты о необработанных исключениях в основном потоке пользовательского интерфейса, фоновых потоках пользовательского интерфейса и BackgroundWorker экземпляров.

Вероятная точка отказа с AppDomain.UnhandledException — диалоговое окно отчета, вероятно, требует однопоточного подразделения (STA), поскольку и WPF, и Windows Forms являются STA. Поскольку потоки пула потоков по умолчанию являются многопоточными подразделениями, необработанное исключение из асинхронной операции в разделе Task.Run(), ThreadPool.QueueUserWorkItem(), IProgress<T>.Report() или многие подобные API приведут к сбою создания экземпляра диалогового окна отчета с чем-то вроде исключения ниже. Это вызывает сбой приложения без возможности предложить пользователю сообщить об основной проблеме.

System.InvalidOperationException: The calling thread must be STA, because many UI components require this.
   at System.Windows.Input.InputManager..ctor()
   at System.Windows.Input.InputManager.GetCurrentInputManagerImpl()
   at System.Windows.Input.KeyboardNavigation..ctor()
   at System.Windows.FrameworkElement.FrameworkServices..ctor()
   at System.Windows.FrameworkElement.EnsureFrameworkServices()
   at System.Windows.FrameworkElement..ctor()
   at System.Windows.Controls.Control..ctor()
   at System.Windows.Window..ctor()

По моему опыту, Application.DispatcherUnhandledException хорошо сочетается с TPL as Task и связанные с ним классы облегчают передачу исключений обратно вызывающей стороне. Подводя итог обработка исключений TPL, Wait() и await перебрасываются автоматически, и вызывающие абоненты, использующие другие методы синхронизации, должны проверить Task.Exception.

Однако, как указано в документации Application.DispatcherUnhandledException, в других случаях требуется, чтобы вызывающая сторона WPF реализовывала распространение исключений. Возможно, наиболее распространенным из них является Progress<T> WPF, который странно отсутствует поддержка распространения исключений из реализации IProgress<T>.Report(), хотя его единственной целью является перемещение информации о ходе выполнения из рабочих потоков обратно в пользовательский интерфейс. Один из способов обхода — обернуть обработчик обновления хода выполнения, используя подход, аналогичный приведенному ниже примеру. Это всего лишь набросок; более частый опрос свойства Exception может быть полезен для остановки при ошибках, более строгая семантика IDisposable может быть предпочтительнее End(), и может быть полезно по-разному обрабатывать случаи, когда невыполненные обновления одновременно терпят неудачу.

public class ExceptionPropagatingProgress<TProgress>
{
    private readonly Action<TProgress> onProgressUpdateCore;
    private readonly IProgress<TProgress> progress;

    public Exception Exception { get; private set; }

    public ExceptionPropagatingProgress(Action<TProgress> handler)
    {
        this.Exception = null;
        this.onProgressUpdateCore = handler ?? throw new ArgumentNullException(nameof(handler));
        this.progress = new Progress<TProgress>(this.OnProgressUpdate);
    }

    public void End()
    {
        if (this.Exception != null)
        {
            throw new AggregateException(this.Exception);
        }
    }

    private void OnProgressUpdate(TProgress value)
    {
        try
        {
            this.onProgressUpdateCore(value);
        }
        catch (Exception exception)
        {
            lock (this.onProgressUpdateCore)
            {
                if (this.Exception == null)
                {
                    this.Exception = exception;
                }
                else
                {
                    this.Exception = new AggregateException(this.Exception, exception);
                }
            }
        }
    }

    public void QueueProgressUpdate(TProgress value)
    {
        if (this.Exception != null)
        {
            throw new AggregateException(this.Exception);
        }

        this.progress.Report(value);
    }
}
person Todd West    schedule 27.02.2019

Вы должны обработать событие Application.ThreadException.

person SLaks    schedule 18.05.2011
comment
Не существует для приложения WPF. - person O'Rooney; 28.06.2013