当我await
关于抛出异常的方法时,尝试/ catch不会将应用程序保存为崩溃。
有投掷方法
void CurrentStep.Process(CancellationToken cancellationToken)
{
throw new Exception();
}
通过ICommand.Execute()
ProcessCurrentStepCommand = AsyncCommandFactory.Create(async cancellationToken =>
{
try
{
await Task.Run(() => CurrentStep.Process(cancellationToken));
}
catch {}
CurrentStep = CurrentStep.NextStepViewModel;
});
ProcessCurrentStepCommand
绑定到UI上的按钮。当我单击按钮时,我的应用程序会中断。
我觉得在UI线程上抛出异常存在一个普遍的问题,但同时我也不明白为什么catch block不会让我免于例外。
我现在找到了对我有用的唯一方法:
await Task.Factory.StartNew(
action: () => CurrentStep.Process(cancellationToken),
creationOptions: TaskCreationOptions.LongRunning);
但它看起来很难看。如果我将来忘记了我想用这段代码做什么,我可能会认为我需要清理它并遇到一些例外,这会导致整个应用程序崩溃。
在调试模式下,一切都很好。
调用堆栈:
UI.exe !UI.Steps.ViewModels.SvmConnectionViewModel.Process(System.Threading.CancellationToken 的CancellationToken)
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(对象 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行
NotImplementedException occured: A first chance exception of type 'System.NotImplementedException' occurred in mscorlib.dll
中的 TaskAwaiter.cs 中。
调用堆栈:
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 cancellationToken)第18行 [恢复异步方法]
的 mscorlib.dll中!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(对象 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(对象 国家)393行 的 WindowsBase.dll中!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback,object args,int numArgs)第118行未知
的 WindowsBase.dll中!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(对象 source,System.Delegate方法,对象args,int numArgs, System.Delegate catchHandler)第41行未知
的 WindowsBase.dll中!System.Windows.Threading.DispatcherOperation.InvokeImpl() 583行未知
的 WindowsBase.dll中!System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(对象 国家)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)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(对象 o)494行未知 的 WindowsBase.dll中!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback,object args,int numArgs)第111行未知 的 WindowsBase.dll中!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(对象 source,System.Delegate方法,对象args,int numArgs, System.Delegate catchHandler)第41行未知
的 WindowsBase.dll中!System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority priority,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)Line 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)Line 2031
Microsoft.VisualStudio.HostingProcess.Utilities.dll !Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()未知 的 mscorlib.dll中!System.Threading.ThreadHelper.ThreadStart_Context(对象 国家)第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回调,对象 520)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.Task 任务)第66行 [异步通话]
UI.exe !UI.Commands.AsyncCommand.ExecuteAsync(对象参数)第55行 [异步通话]
UI.exe !UI.Commands.AsyncCommandBase.Execute(对象参数)第15行
调用堆栈:
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令牌)第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任务)第66行 [恢复异步方法]
...
<Label Content="{Binding ProcessCurrentStepCommand.Execution.ErrorMessage}" Visibility="{Binding ProcessCurrentStepCommand.Execution.IsFaulted, Converter={StaticResource BooleanToVisibilityConverter}}" />
要了解问题的背景和接受的答案,您需要查看这些文章:
答案 0 :(得分:4)
我不想将异常直接传播回主UI循环;我想捕获任何异常并设置属性,以便通过数据绑定完成错误处理。
在这种情况下,您真正需要的是同步命令,只需启动异步操作,其中异步操作使用NotifyTaskCompletion
表示(或你写的一些类似的类型)。像这样分解操作(进入同步“开始”和异步数据绑定)比尝试一次完成更容易(这也是可能的 - 只是代码不是那么短或可重用):
// Represents the execution of the current step.
NotifyTaskCompletion ProcessCurrentStepCommandExecution
{
get { return _processCurrentStepCommandExecution; }
set { _processCurrentStepCommandExecution = value; PropertyChanged(); }
}
...
var cancellationToken = ...; // Wherever you get this from.
ProcessCurrentStepCommand = new DelegateCommand(() =>
{
ProcessCurrentStepCommandExecution = new NotifyTaskCompletion(async () =>
{
await Task.Run(() => CurrentStep.Process(cancellationToken));
// I'm assuming here you only want to move to the next step if there are no errors.
// Otherwise, this should be in a finally block.
CurrentStep = CurrentStep.NextStepViewModel;
});
});
修改强>
我相信你可能会遇到该文章示例代码中的错误(在MSDNMag决定删除它们之前,评论中曾经有更新的代码,我正在努力更新代码示例,令人惊讶的漫长过程)。如果任务同步完成(异常或成功),则会发生错误;在这种情况下,NotifyTaskCompletion<T>.TaskCompleted
将为null
。
要解决此问题,请从此处更改NotifyTaskCompletion<T>
的构造函数:
{
Task = task;
if (!task.IsCompleted)
TaskCompletion = WatchTaskAsync(task);
}
到此:
{
Task = task;
TaskCompletion = WatchTaskAsync(task);
}