Подтвердить что ты не робот

Необработанный обработчик исключений не вызван для обработчика событий async void для Metro/WinRT UI

Считайте следующее: выдержки из приложения Windows 8 Metro/WinRT, которые были уменьшены до минимального минимума, необходимого для отображения аномалии:

public class App : Application
{
    public App()
    {
        UnhandledException += (sender, e) => e.Handled = true;
    }
}

public class MainPage : Page
{
    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        throw new NotSupportedException();
    }

    private async void Button_Click_2(object sender, RoutedEventArgs e)
    {
        throw new NotSupportedException();
    }
}

Поэтому, учитывая интерфейс Metro с двумя кнопками и обработчиками событий кликов, единственное отличие состоит в том, что второй обработчик событий помечен как async.

Затем, щелкая по каждой кнопке, я ожидаю, что обработчик UnhandledException будет вызван в обоих случаях, так как они должны быть введены через поток пользовательского интерфейса и связанный с ним контекст синхронизации. Мое понимание заключается в том, что для методов async void любые исключения должны быть захвачены и "возвращены" (сохраняются исходные стекы) через исходный контекст синхронизации, что также четко указано в "Часто задаваемые вопросы по Async/Await" .

Но обработчик UnhandledException имеет не, вызванный в случае async, поэтому приложение аварийно завершает работу! Поскольку это бросает вызов тому, что я считаю совершенно интуитивной моделью, мне нужно знать, почему! Да, я знаю, что я мог бы обернуть тело обработчика в try { } catch { }, но мой вопрос в том, почему он не обратный обработчик UnhandledException?

Чтобы еще раз подчеркнуть, почему это не имеет смысла, рассмотрите следующие практически идентичные выдержки из приложения WPF, также используя async/wait и Targeting.NET Framework 4.5:

public class App : Application
{
    public App()
    {
        DispatcherUnhandledException += (sender, e) => e.Handled = true;
    }
}

public class MainWindow : Window
{
    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        throw new NotSupportedException();
    }

    private async void Button_Click_2(object sender, RoutedEventArgs e)
    {
        throw new NotSupportedException();
    }
}

[Существует тонкая разница в том, что WPF имеет обработчик событий Application DispatcherUnhandledException, а также обработчик событий AppDomain UnhandledException, но вы можете только отмечать исключение как "обработанное" в DispatcherUnhandledException, которое согласуется с приложением Metro/WinRT Обработчик события UnhandledException выше.]

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

4b9b3361

Ответ 3

Как описано в документации (источник: http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.application.unhandledexception.aspx):

Важно знать несколько ограничений Событие Application.UnhandledException. Это событие используется только с исключения, встречающиеся в рамках XAML. Исключения другими компонентами Windows Runtime или частями приложения, которые не связаны с базой XAML, не приведет к этому событию поднимается.

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

Как указано в этот разговор, только способ получения исключений, происходящих в рабочем потоке, состоит в том, чтобы обернуть их в try/catch. Как следствие, здесь обходной путь, который я использую в своем приложении: вместо использования Task.Run или эквивалентов для выполнения кода в рабочем потоке из пользовательского интерфейса я использую этот метод:

/// <summary>
/// Runs code in a worker thread and retrieves a related exception if any.
/// </summary>
/// <param name="target">The target.</param>
/// <param name="action">The action.</param>
public static void SafeRun(this DependencyObject target, Action action)
{
    Task task = ThreadPool.RunAsync(o =>
    {
        try
        {
            action();
        }
        catch (Exception ex)
        {
            /* Call the same error logging logic as in the UnhandledException event handler here. */
        }
    }).AsTask();
    task.Wait();
}

Нижняя строка заключается в том, что для регистрации всех ошибок в вашем приложении вам необходимо:

  • Подписывать событие UnhandledException для получения ошибок, связанных со стеком XAML,
  • Действия обертывания в рабочих потоках в блоке try/catch.

Ответ 4

С моей точки зрения, единственное правильное решение было остановлено здесь (Try UnobservedTaskException event TaskScheduler)

проблема в том, что вы используете "async void", где исключения не могут быть обработаны. Это не ограничение WinRT, а как поведение при проектировании async. Вам нужно понять, насколько асинхронно нужно правильно выполнять обработку исключений. См. Эту статью: http://msdn.microsoft.com/en-us/magazine/jj991977.aspx

Исключены исключения. GC собирает задачи как незаметные. Вы можете получить их, зарегистрировав событие TaskScheduler UnobservedTaskException. Примечание. Требуется некоторое время до появления исключения, потому что оно отмечено сборщиком мусора.

Как правило, не используйте "async void", но в обработчиках событий UI вы должны, так что это ваш единственный способ.

Ответ 5

Попробуйте событие UnobservedTaskException для TaskScheduler