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.