Перехват исключений в WPF на уровне FrameWork - PullRequest
3 голосов
/ 07 января 2011

Я занимаюсь разработкой облегченного WPF MVVM-фреймворка и хотел бы иметь возможность отлавливать необработанные исключения и в идеале восстанавливаться после них.

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

Если я зарегистрирую обработчик для AppDomain.CurrentDomain.UnhandledException в методе OnStartup файла App.xaml.cs, как показано ниже ...

App.xaml.cs:

protected override void OnStartup(StartupEventArgs e)
{
  AppDomain.CurrentDomain.UnhandledException += new
     UnhandledExceptionEventHandler(this.AppDomainUnhandledExceptionHandler); 

  base.OnStartup(e);
}


 void AppDomainUnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs ea)
{
  Exception e = (Exception)ea.ExceptionObject;
  // log exception
}

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

Пока все хорошо, за исключением того факта, что я не могу восстановить с помощью этого подхода, все, что я могу сделать, - записать исключение и затем позволить CLR завершить приложение.

Что я на самом деле хотел сделать, так это восстановить и вернуть управление основной виртуальной машине. (Опять откладывая мотивы против этого).

Итак, читая, я решил зарегистрировать обработчик событий для AppDomain.CurrentDomain.UnhandledException в том же месте, чтобы код теперь выглядел примерно так ...

protected override void OnStartup(StartupEventArgs e)
{
  AppDomain.CurrentDomain.UnhandledException += 
    new UnhandledExceptionEventHandler(this.AppDomainUnhandledExceptionHandler); 

  this.DispatcherUnhandledException += 
    new DispatcherUnhandledExceptionEventHandler(DispatcherUnhandledExceptionHandler);

  base.OnStartup(e);
}

void AppDomainUnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs ea)
{
  Exception e = (Exception)ea.ExceptionObject;
  // log exception
}

void DispatcherUnhandledExceptionHandler(object sender, DispatcherUnhandledExceptionEventArgs args)
{
  args.Handled = true;
  // implement recovery
}

Проблема заключается в том, что как только я регистрирую обработчик для этого. DispatcherUnhandledException НИКОГДА НЕ ВЫЗЫВАЕТСЯ ХЕНДЛЕР. Поэтому регистрация DispatcherUnhandledExceptionHandler каким-то образом деактивирует обработчик для AppDomain.CurrentDomain.UnhandledException.

Есть ли у кого-нибудь подход для перехвата и восстановления после необработанных исключений ВМ?

Может быть важно упомянуть, что в фреймворке нет явного использования многопоточности.

Ответы [ 2 ]

5 голосов
/ 07 января 2011

Причина, по которой VS показывает вам исключение, заключается в том, что вы настроили его таким образом (либо вы сделали это явно, либо, что более вероятно, значения по умолчанию в VS настроили его так).Вы можете контролировать действия Visual Studio, когда он обнаруживает исключение в отлаженном коде, через меню Debug->Exceptions.

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

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

2 голосов
/ 04 марта 2013

Быстрый ответ на мой вопрос:

Это работает ...

App.xaml.cs:

protected override void OnStartup(StartupEventArgs e)
{
  Application.Current.DispatcherUnhandledException +=
    new DispatcherUnhandledExceptionEventHandler(DispatcherUnhandledExceptionHandler);

  base.OnStartup(e);
}

void DispatcherUnhandledExceptionHandler(object sender, DispatcherUnhandledExceptionEventArgs args)
{
  args.Handled = true;
  // implement recovery
  // execution will now continue...
}

[Edit: Мои комментарии ниже не имеют ничего общего с реализацией, но моя конкретная конфигурация IDE (Visual Studio) в отношении перехвата исключений в IDE. Пожалуйста, смотрите комментарии Исака выше.]

НО, и это большое, но, если вы выполняете из VisualStudio, ВЫ ПОЖАЛУЙСТА ПОЛУЧИТЕ диалоговое окно с уведомлением об исключении VS, и DispatcherUnhandledExceptionHandler будет вызываться только при нажатии F5 / continue, после чего выполнение будет продолжаться в обычном режиме.

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

...