WPF - перехват исключений в коде, выполняемом шиной сообщений SimpleMVVM

Я создаю приложение WPF с использованием инфраструктуры SimpleMVVM, и у меня возникают проблемы с обнаружением исключений. Я использую MessageBus от SimpleMVVM, чтобы отправить сообщение другой модели представления. Все это прекрасно работает, но я заметил, что исключения, возникающие в коде, выполняемом шиной сообщений, подавляются. Вот что у меня так далеко:

мой MainWindow содержит кнопку, которая запускает TempCommand на MainWindowViewModel. Эта команда в свою очередь вызывает Test метод (показанный ниже), который отправляет уведомление с помощью MessageBus из SimpleMVVM.

private void Temp()
{
    SendMessage("Temp", new NotificationEventArgs());
}

мой MainWindow также содержит Frame с содержанием. ViewModel этого контента, CustomerViewModel, зарегистрировался для получения этих уведомлений в своем конструкторе:

public CustomerDetailsViewModel(ICustomerServiceAgent agent)
{
    RegisterToReceiveMessages("Temp", Temp);
}

Где Temp Метод просто выдает исключение:

private void Temp(object sender, NotificationEventArgs args)
{
    throw new NotImplementedException("Somewhere, something horrible happened");
}

Когда я отлаживаю приложение, я ясно вижу Temp вызываемый метод и возбуждаемое исключение. Но по какой-то причине это все. Приложение не затронуто, и мой код перехвата исключений не знает об этом исключении.

Я ловлю исключения двумя способами. Первый заключается в обработке события на Dispatcher:

<Application x:Class="MyApp"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml"
             DispatcherUnhandledException="App_DispatcherUnhandledException">

Где выглядит код программы:

private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
    Log("Exception: " + e.Exception.Message);
    e.Handled = true;
}
public static void Log(string message)
{
    File.AppendAllText(@"D:\Temp\log.txt", "[" + DateTime.Now.ToString("F") + "] [" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString() + "] " + message + Environment.NewLine);
}

Этот код ловит некоторые исключения, но не все. Я обнаружил, что WPF по умолчанию подавляет исключения привязки данных. Потому что мои ViewModels ограничены через DataContext собственность на мой взгляд, я думал, что это проблема. Я нашел эту статью, которая определяет TraceListener который использует PresentationTraceSources учебный класс. Исключения привязки данных теперь перехватываются, но... Не исключение, которое выдается в коде, выполняемом через MessageBus.

Я создал решение, демонстрирующее такое поведение, его можно скачать здесь.

И вот где я застрял. Что мне не хватает? Как мне поймать эти исключения?

Большое спасибо заранее.

JP

1 ответ

Решение

Я думаю, что это ошибка или проблема с реализацией MessageBus в SimpleMVVM.

Поскольку несколько подписчиков могут подписаться на токен, текущая реализация гарантирует, что каждый подписанный метод вызывается, даже если один зарегистрированный метод вызывает исключение. В этом случае исключение перехватывается и записывается на консоль.

Метод, который отвечает за вызов подписанного метода, - SafeNotify.

private void SafeNotify(Action method, bool post) {
  try {
    // Fire the event on the UI thread
    if (post){
      if (Dispatcher.CheckAccess()){
        method();
      }
      else{
        Dispatcher.BeginInvoke(method);
      }
    }
    // Fire event on a ThreadPool thread
    else{
      ThreadPool.QueueUserWorkItem(o => method(), null);
    }
  }
  catch (Exception ex){
    // If there's an exception write it to the Output window
    Debug.WriteLine(ex.ToString());
  }
}

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

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

Другие вопросы по тегам