为了健壮,我想为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
答案 0 :(得分:1)
这是一个非常好的问题。由于此事件在终结器线程上运行(我已经使用Reflector确认了这一点),因此我们无法在延长的时间段内阻止。这将阻止终结者被处理。
所以答案是:这不是一个好的设计,因为UI操作的持续时间是无限的。
更好的解决方案是将处理排队到新的Task
,以便它在线程池上运行。
此答案取决于实现细节(在单个线程上执行终结器以及在终结器线程上触发事件)。但至少对于支持.NET 4.0的应用程序,这个答案是有效的。