考虑下面是从Windows 8地铁/ 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 UI有两个按钮和他们的点击事件处理程序,唯一的区别是,第二个事件处理程序被标记为async
。
然后点击每个按钮,我预计UnhandledException处理程序,在两种情况下被调用,因为他们(应该)都可以通过UI线程进入和相关的同步上下文。 我的理解的是,对于async void
的方法,任何例外应当被捕获和“重新抛出”(保留原始堆栈跟踪)经由初始同步环境,这也清楚地以所述异步/等待FAQ 。
但UnhandledException处理程序没有在所谓的async
的情况下,这样的应用程序崩溃! 由于这个挑战我认为否则很直观的模型,我需要知道为什么! 是的,我知道我可以包处理程序的身体处于try { } catch { }
但我的问题是,为什么不叫逆止UnhandledException处理?
为了进一步强调为什么这没有任何意义,可考虑从一个WPF应用程序也使用异步/等待并针对.NET框架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既有的应用程序DispatcherUnhandledException事件处理程序,以及一个AppDomain UnhandledException事件处理一个微妙的差异,但在DispatcherUnhandledException,它与地铁/ WinRT的应用UnhandledException事件处理程序对齐为“处理”,你只能标记异常以上。]
然后点击每个按钮时,DispatcherUnhandledException处理器的确是叫在两种情况下,如预期,并且应用程序不会崩溃。
在这里找到答案: 没有UnhandledException从异步事件回调解雇
这是的WinRT的一个已知的限制。 我们希望,它被固定在下次更新。
在以下职位的解决方案为我,一个小的变化:我不得不搬到AsyncSynchronizationContext.Register(); 到App.OnLaunched事件
http://www.markermetro.com/2013/01/technical/handling-unhandled-exceptions-with-asyncawait-on-windows-8-and-windows-phone-8/
如文档中说明的(来源: http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.application.unhandledexception.aspx ):
需要注意的Application.UnhandledException事件的一些局限性是很重要的。 此事件只使用由XAML框架中遇到异常。 其它Windows运行时组件或没有连接到XAML框架的应用程序不会导致此事件的部分地区遭遇异常被提出。
例如,如果一个不同的Windows组件调用应用程序代码中,并抛出一个异常,并没有被捕获,UnhandledException事件将不会引发。 如果应用程序创建一个工作线程,然后提高了工作线程上的异常,UnhandledException事件将不会引发。
正如指出的这段对话 , 只有这样,才能检索例外的工作线程发生是包装他们在一个try / catch块 。 因此,这里是我用我的应用程序解决方法:而不是使用Task.Run
或等同于从UI工作者线程执行代码,我用这个方法:
/// <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();
}
底线是,登录您的应用程序,则应该将所有的错误:
- Subscribre到UnhandledException事件得到XAML堆栈相关的错误,
- 在包裹在一个try / catch块一个工作线程发生的动作。
从我的观点是唯一正确的answere在这里downvoted点(尝试的TaskScheduler的UnobservedTaskException事件)
问题是,你正在使用“异步无效”,其中的例外无法处理。 这不是一个WinRT的限制,但作为异步的设计行为。 你需要了解异步深深正确这里执行异常处理。 看到这篇文章: http://msdn.microsoft.com/en-us/magazine/jj991977.aspx
异常被再次抛出磨片GC收集任务未观察到的。 您可以通过注册的TaskScheduler UnobservedTaskException事件得到他们。 注 - 这需要一些时间,直到例外到达那里,因为它是与垃圾收集指出。
一般情况下不要“异步无效”使用,但在UI事件处理程序,你必须这样做,所以这是你唯一的办法..
尝试的TaskScheduler的UnobservedTaskException事件
文章来源: Unhandled exception handler not called for Metro / WinRT UI async void event handler