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

时间:2012-09-01 08:39:57

标签: .net vb.net exception-handling task-parallel-library

为了健壮,我想为TaskScheduler.UnobservedTaskException添加一个处理程序。 处理程序会记录Exception(s)通知用户并关闭应用程序。

以下实施是否有意义? 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

End Sub

[编辑] 由于我们的讨论,我提出了以下解决方案。

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 个答案:

答案 0 :(得分:1)

这是一个非常好的问题。由于此事件在终结器线程上运行(我已经使用Reflector确认了这一点),因此我们无法在延长的时间段内阻止。这将阻止终结者被处理。

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

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

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