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
4

1 回答 1

1

这个问题问得好。由于此事件在终结器线程上运行(我已通过 Reflector 确认了这一点),因此我们不能长时间阻塞。这将停止处理终结器。

所以答案是:这不是一个好的设计,因为 UI 操作的持续时间是无限的。

更好的解决方案是将处理排队到一个新的Task,以便它在线程池上运行。

这个答案取决于实现细节(终结器在单个线程上执行,事件在终结器线程上触发)。但至少对于支持 .NET 4.0 的应用来说,这个答案是有效的。

于 2012-09-01T21:16:33.570 回答