取消在.Net中引发未处理的异常

取消在.Net中引发未处理的异常,.net,vb.net,task,task-parallel-library,cancellationtokensource,.net,Vb.net,Task,Task Parallel Library,Cancellationtokensource,这似乎是一个常见的问题,但我还无法找到解决方案。我这么早就登记了 我的来电者: Private Async Sub btnTestTimer_Click(sender As Object, e As EventArgs) Handles btnTest.Click _cts = New CancellationTokenSource() Try Await Task.Run(AddressOf TestCancellationAsync).Configu

这似乎是一个常见的问题,但我还无法找到解决方案。我这么早就登记了

我的来电者:

    Private Async Sub btnTestTimer_Click(sender As Object, e As EventArgs) Handles btnTest.Click
    _cts = New CancellationTokenSource()
    Try
        Await Task.Run(AddressOf TestCancellationAsync).ConfigureAwait(False)
    Catch cx As OperationCanceledException
        MsgBox(String.Format("The following error occurred: {0}", cx.Message), MsgBoxStyle.Critical)
    Catch ex As Exception
        MsgBox(String.Format("The following error occurred: {0}", ex.Message), MsgBoxStyle.Critical)
    End Try
End Sub
我的任务在这里

    Private Async Function TestCancellationAsync() As Task
        'Launch a dummy timer which after some time will itself cancel a token and throw
        Dim tmr As New System.Timers.Timer(1000)
        AddHandler tmr.Elapsed, AddressOf OnTimerElapsed
        tmr.Enabled = True
    End Function
取消和抛出的计时器功能是

    Private Sub OnTimerElapsed(sender As Object, e As ElapsedEventArgs)
        Dim tmr As System.Timers.Timer = CType(sender, System.Timers.Timer)
        tmr.Enabled = False
        Task.Delay(5000) 'After 5 seconds simulate a cancellation
        _cts.Cancel() //This is just to cancel from within the timer, actually the cancellation to _cts will happen from another caller which is not shown here
        _cts.Token.ThrowIfCancellationRequested()
    End Sub
这里不显示包含异步任务和取消的实际程序,以保持示例简洁,同时仍然能够复制问题

业务需求是,单击一个按钮,将启动一个异步任务,这将打开几个异步函数。其中一个将启动一个计时器,该计时器将持续检查_cts令牌状态,并在需要时取消。如果在_cts令牌上从外部发生这种取消,计时器将抛出取消异常

我尝试过的事情:

  • 我已经处理了OperationCancelled异常,但仍然没有处理
  • 我已取消选中工具选项调试常规仅启用我的代码,以查看它是否只是VisualStudio。但仍报告为PDB未处理异常
  • 我已经从外部运行了exe,正如预期的那样,它由于未处理的异常而崩溃

一定要让我知道我做错了什么。我的调用者等待任务完成——因为任务内部正在运行计时器,所以我希望任务没有完成,引发的任何异常都会被捕获

我认为在这种情况下,计时器是问题所在。创建并让计时器从任务中触发,然后从计时器处理方法中抛出取消异常,这样做不起作用,因为一旦创建并启用计时器,任务将返回,而不等待计时器完成。这意味着
TestCancellationAsync
方法不会等待计时器代码触发并保持任务。它立即返回给调用者。
btnTestTimer\u Click
中的调用者认为任务已返回并退出try并结束该方法。这意味着没有有效的事件处理程序来捕获计时器引发的异常。这将导致未处理的异常

解决方案是使用具有相关延迟的无限循环来模拟计时器,并从内部调用计时器代码,而不创建计时器对象

因此,应将
TestCancellationAsync
更改为如下所示

    Private Async Function TestCancellationAsync() As Task
    'Simulate a timer behaviour
    While True
        Await DoWorkAsync().ConfigureAwait(False)
        Await Task.Delay(1000).ConfigureAwait(False)
    End While
End Function
然后可以将
ontimerecursed
这实际上是worker函数更改为

Private Async Function DoWorkAsync() As Task
    'Do work code
    _cts.Token.ThrowIfCancellationRequested()
End Sub
现在,如果从外部取消cts,它将被捕获


这解决了当前的问题。

无论是谁否决了这个问题,请解释原因