在GUI应用程序中,处理TaskScheduler.UnobservedTaskException的推荐方法是什么?

3
为了提高健壮性,我想添加一个处理程序来处理TaskScheduler.UnobservedTaskException。 该处理程序将记录异常信息并通知用户关闭应用程序。
以下是实现的示例,你觉得它合理吗? 在这个处理程序中,在WPF中显示一个MessageBox或Windows是否可行?或者说这是一个坏主意,因为我们正在运行未观察到的任务的终结器?
Private Sub TaskSheduler_UnobservedTaskException(sender As Object, e As UnobservedTaskExceptionEventArgs)
Static _wasUserInformed As Boolean = False

e.SetObserved()

'Trace all Exceptions
e.Exception.Flatten.Handle(Function(ex As Exception)
                               'TODO trace and log Exception
                               Debug.Print("UnobservedTaskException: {0}", ex.Message)
                               Return True
                           End Function)

If Not _wasUserInformed Then
    'Show root Exception 
    _wasUserInformed = True
    Application.Current.Dispatcher.BeginInvoke(Sub()
                                                   'MessageBox.Show(e.Exception.GetBaseException.Message)

                                                   Dim win As New UnexpectedExceptionWindow
                                                   win.UnexpectedException = e.Exception.GetBaseException
                                                   win.ShowDialog()

                                                   Application.Current.Dispatcher.BeginInvoke(Sub() Application.Current.Shutdown())
                                               End Sub)
End If

结束子程序

[编辑] 我们的讨论得出以下解决方案。

Private Sub TaskScheduler_UnobservedTaskException(sender As Object, e As UnobservedTaskExceptionEventArgs
                                                  ) Handles TaskScheduler.UnobservedTaskException
    Static _wasUserInformed As Boolean = False

    'Free the finalizer thread and execute on the UI thread to be able to inform user
    Dispatcher.BeginInvoke(Sub() LogException(e.Exception))
    e.SetObserved()
    If Not _wasUserInformed Then
        _wasUserInformed = True
        'Show first error 
        Dispatcher.BeginInvoke(Sub()
                                   NotifyUser(e.Exception)
                                   Application.Current.Shutdown()
                               End Sub)
    End If
End Sub
1个回答

1
这是一个非常好的问题。由于此事件正在运行在终结器线程上(我已经通过Reflector确认了这一点),我们不能承受长时间的阻塞。这将停止终结器的处理。
所以答案是:这不是一个好的设计,因为UI操作的持续时间是不确定的。
更好的解决方案是将处理排队到一个新的Task中,以便它在线程池上运行。
这个答案取决于实现细节(终结器在单个线程上执行,事件在终结器线程上触发)。但至少对于支持.NET 4.0的应用程序来说,这个答案是有效的。

然而,他也在调用Dispatcher.BeginInvoke,所以真正阻塞终结器的只是调试打印。如果他也将其包含在BeginInvoke操作中,那么就不会有太多的阻塞发生。 - Matt H

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接