【发布时间】:2015-10-11 12:49:36
【问题描述】:
当我 await 在一个引发异常的方法上时,try/catch 不会使应用程序崩溃。
有一种投掷方法
void CurrentStep.Process(CancellationToken cancellationToken)
{
throw new Exception();
}
通过ICommand.Execute()的方式从UI线程调用
ProcessCurrentStepCommand = AsyncCommandFactory.Create(async cancellationToken =>
{
try
{
await Task.Run(() => CurrentStep.Process(cancellationToken));
}
catch {}
CurrentStep = CurrentStep.NextStepViewModel;
});
ProcessCurrentStepCommand 绑定到 UI 上的按钮。当我单击按钮时,我的应用程序会中断。
我觉得在 UI 线程上抛出异常是一个普遍的问题,但同时我不明白为什么 catch 块不能将我从异常中拯救出来。
我现在找到了唯一适合我的方法:
await Task.Factory.StartNew(
action: () => CurrentStep.Process(cancellationToken),
creationOptions: TaskCreationOptions.LongRunning);
但它看起来很丑。如果我以后忘记了我想对这段代码做什么,我可能会认为我需要清理它并遇到一些异常会导致整个应用程序崩溃。
在调试模式下,一切正常。
调用栈:
UI.exe!UI.Steps.ViewModels.SvmConnectionViewModel.Process(System.Threading.CancellationToken cancelToken)
UI.exe!UI.MainViewModel..ctor.AnonymousMethod__1() 第 18 行 mscorlib.dll!System.Threading.Tasks.Task.InnerInvoke() 第 2911 行 mscorlib.dll!System.Threading.Tasks.Task.Execute() 第 2523 行 mscorlib.dll!System.Threading.Tasks.Task.ExecutionContextCallback(object obj) 第 2888 行 mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext、System.Threading.ContextCallback 回调、对象 state, bool preserveSyncCtx) 第 581 行
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext、System.Threading.ContextCallback 回调、对象 state, bool preserveSyncCtx) 第 531 行
mscorlib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot) 第 2853 行 mscorlib.dll!System.Threading.Tasks.Task.ExecuteEntry(bool bPreventDoubleExecution) 第 2792 行 mscorlib.dll!System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() 第 2729 行
mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch() 第 830 行 mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() 1171号线
- 在 TaskAwaiter.cs 方法 ThrowForNonSuccess() 中发生下一个中断:
NotImplementedException occured: A first chance exception of type 'System.NotImplementedException' occurred in mscorlib.dll。
调用栈:
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task 任务)第 180 行
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task 任务)第 170 行
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.GetResult() 第 125 行
UI.exe!UI.MainViewModel..ctor(System.Threading.CancellationToken cancelToken) 第 18 行
[恢复异步方法]
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine) 第 1065 行
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext、System.Threading.ContextCallback 回调、对象 state, bool preserveSyncCtx) 第 581 行
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext、System.Threading.ContextCallback 回调、对象 state, bool preserveSyncCtx) 第 531 行
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run() 第 1045 行
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.OutputAsyncCausalityEvents>.AnonymousMethod__0() 第 973 行
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke() 第 1085 行
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.OutputWaitEtwEvents.AnonymousMethod__0() 第 301 行
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke() 第 1085 行
mscorlib.dll!System.Threading.Tasks.SynchronizationContextAwaitTaskContinuation.GetActionLogDelegate.AnonymousMethod__3() 第 470 行
mscorlib.dll!System.Threading.Tasks.SynchronizationContextAwaitTaskContinuation..cctor.AnonymousMethod__6(object 状态)第 393 行
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs) Line 118 Unknown
WindowsBase.dll!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(object 源,System.Delegate 方法,对象 args,int numArgs, System.Delegate catchHandler) 第 41 行未知
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.InvokeImpl() 第 583 行未知
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(object 状态)第 528 行未知
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext、System.Threading.ContextCallback 回调、对象 state, bool preserveSyncCtx) 第 581 行
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext、System.Threading.ContextCallback 回调、对象 state, bool preserveSyncCtx) 第 531 行
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext、System.Threading.ContextCallback 回调、对象 状态)第 520 行
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.Invoke() 第 441 行未知
WindowsBase.dll!System.Windows.Threading.Dispatcher.ProcessQueue() 第 2227 行未知
WindowsBase.dll!System.Windows.Threading .Dispatcher.WndProcHook(System.IntPtr hwnd,int msg,System.IntPtr wParam,System.IntPtr lParam,ref bool 已处理)第 2480 行未知
WindowsBase.dll!MS.Win32.HwndWrapper.WndProc(System.IntPtr hwnd,int msg,System.IntPtr wParam,System.IntPtr lParam,ref bool 已处理) 第 345 行未知
WindowsBase.dll!MS.Win32.HwndSubclass.DispatcherCallbackOperation(object o) 第 494 行未知 WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs) Line 111 Unknown WindowsBase.dll!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(object 源,System.Delegate 方法,对象 args,int numArgs, System.Delegate catchHandler) 第 41 行未知
WindowsBase.dll!System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority 优先级、System.TimeSpan 超时、System.Delegate 方法、对象 args, int numArgs) 第 1447 行未知 WindowsBase.dll!MS.Win32.HwndSubclass.SubclassWndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam) 行 398 未知
[本地到托管转换]
[托管到本地转换]
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame 框架)第 2281 行未知
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame 框架)第 369 行未知
WindowsBase.dll!System.Windows.Threading.Dispatcher.Run() 第 328 行未知
PresentationFramework.dll!System.Windows .Application.RunDispatcher(对象 忽略)第 2745 行
PresentationFramework.dll!System.Windows.Application.RunInternal(System.Windows.Window 窗口) 1841 号线 PresentationFramework.dll!System.Windows.Application.Run(System.Windows.Window 窗口)第 261 行 PresentationFramework.dll!System.Windows.Application.Run() 第 222 行 UI.exe!UI.App.Main() [本机到托管转换]
mscorlib.dll!System.AppDomain.ExecuteAssembly(string assemblyFile, System.Security.Policy.Evidence assemblySecurity, string[] args) 行 2031
Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 未知 mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object 状态)第 74 行
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext、System.Threading.ContextCallback 回调、对象 state, bool preserveSyncCtx) 第 581 行
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext、System.Threading.ContextCallback 回调、对象 state, bool preserveSyncCtx) 第 531 行
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext、System.Threading.ContextCallback 回调、对象 state) 第 520 行
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() 第 111 行
[异步调用]
UI.exe!UI.Commands.AsyncCommandFactory.Create(System.Threading.CancellationToken 令牌)第 27 行
[异步调用]
UI.exe!UI.NotifyTaskCompletion.WatchTaskAsync(System.Threading.Tasks 。任务 任务)第 66 行
[异步调用]
UI.exe!UI.Commands.AsyncCommand.ExecuteAsync(对象参数)第 55 行
[异步调用]
UI.exe!UI.Commands.AsyncCommandBase.Execute(object parameter) 第 15 行
- 下一个 break 具有相同的异常并且与上一个堆栈跟踪几乎相同(区别仅在于最后调用的 4 个方法中的第一个)。
调用栈:
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task 任务)第 180 行
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task 任务)第 170 行
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.GetResult() 第 125 行
UI.exe!UI.Commands.AsyncCommandFactory.Create(System.Threading.CancellationToken token) 第 27 行
[恢复异步方法]
...
- 下一个再次只是在一种方法上有所不同。
调用栈:
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task 任务)第 180 行
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task 任务)第 170 行
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.GetResult() 第 125 行
UI.exe!UI.NotifyTaskCompletion.WatchTaskAsync(System.Threading.Tasks.Task task) 第 66 行
[恢复异步方法]
...
- 在上一次中断之后,不再引发异常,并且 Task.IsFaulted 设置为 true。现在 UI 使用此绑定成功显示异常消息:
<Label Content="{Binding ProcessCurrentStepCommand.Execution.ErrorMessage}" Visibility="{Binding ProcessCurrentStepCommand.Execution.IsFaulted, Converter={StaticResource BooleanToVisibilityConverter}}" />
最终编辑。
要了解问题的上下文和接受的答案,您需要查看以下文章:
【问题讨论】:
-
抛出的异常是什么?你有抛出异常的堆栈跟踪吗?
-
当我在调试模式下启动它时,它的行为会有所不同。我将编辑我的答案以包含这些堆栈跟踪。
-
@Pixar:
catch区块正在捕捉到它。只是调试器先看到它并通知你,仅此而已。 -
@Stephen:是的,我明白这一点。我已经包含了所有这些堆栈跟踪来诊断问题。很高兴您能看到我的问题,因为我使用您的文章创建了异步命令 :) 现在我可以更具体地介绍您的示例 AsyncCommand1、AsyncCommand2、AsyncCommand3 和 AsyncCommand4。如果您在 MyService.DownloadAndCountBytesAsync() 方法的开头添加
throw new Exception(),当您按下Go按钮时,应用程序也会崩溃。 -
@Pixar:是的。命令在概念上类似于事件,如果您从任何事件处理程序(或命令)抛出异常,它将被视为顶级应用程序异常,默认行为为崩溃。您期望的行为是什么?
标签: wpf exception async-await task-parallel-library ui-thread