异步任务功能的异常处理

时间:2019-03-29 10:44:39

标签: vb.net exception async-await

我开始学习有关在VB.NET中运行可取消SQL查询的异步/任务功能。

我在运行两个任务且没有任何异常处理的类库中有以下代码,因为我想在调用类库的应用程序中处理此问题。我在类库中有以下代码。

Public Async Function DirectoryList(ct As CancellationToken) As Task(Of List(Of Directory))
    ct.ThrowIfCancellationRequested()

    Dim ds As DataSet
    Dim dirs As List(Of Directory)
    Dim ctUnregister As CancellationTokenRegistration

    ds = Await Task.Run(Function()
                            Using newConnection = New SqlConnection(Me.InitializationData.ConnectionString)
                                Using sqlAdapter = New SqlDataAdapter("DirectoryList", newConnection)
                                    ctUnregister = ct.Register(Sub() sqlAdapter.SelectCommand.Cancel())

                                    With sqlAdapter
                                        .SelectCommand.CommandType = CommandType.StoredProcedure
                                        .SelectCommand.CommandTimeout = Me.InitializationData.CommandTimeout
                                    End With

                                    Dim newDataSet As DataSet = New DataSet()

                                    sqlAdapter.Fill(newDataSet)
                                    Return newDataSet
                                End Using
                            End Using

                            ' Remove the registration we set earlier so the cancellation token can be used normally.
                            ctUnregister.Dispose()
                        End Function, ct)

    dirs = Await Task.Run(Function()
                              Dim dirsResult As New List(Of Directory)

                              Dim tbl As DataTable = ds.Tables(0)

                              For Each row As DataRow In tbl.Select()
                                  ' process the data

                                  ct.ThrowIfCancellationRequested()
                              Next

                              Return dirsResult
                          End Function, ct)

    Return dirs
End Function

然后我将其称为:

Try
    dirs = Await databaseLibrary.DirectoryList(cts.Token)
    MsgBox("Query complete!")
Catch ex As System.Data.SqlClient.SqlException
    MsgBox("Cancelled (SQL)")
Catch ex2 As OperationCanceledException
    MsgBox("Cancelled")
Catch ex3 As Exception
    MsgBox("Cancelled")
End Try

在功能上似乎可以按预期工作-我可以取消请求,并按预期抛出异常。

但是我想处理异常,以便我可以优雅地取消任务,但是即使在IDE中以“调试”模式运行时,应用程序仍会中断,并且异常(例如SqlException)会显示在IDE中。如果我继续前进,最终将运行Catch逻辑。

当应用程序在IDE外部运行时,异常处理将按预期进行。

这似乎与在调试器中运行时的正常行为不同-通常会运行异常处理,但只有在未处理异常时才会中断。

为什么这种行为不同,大概是由于异步功能造成的?

1 个答案:

答案 0 :(得分:0)

  

在IDE中以“调试”模式运行时,应用仍会中断,并且IDE中会显示异常(例如SqlException)。

     

为什么这种行为不同,大概是由于异步功能造成的?

catch不能直接 捕获异步函数引发的异常。实际发生的情况是,异常是由编译器生成的状态机捕获的,并且该异常被放置在返回的Task上。稍后,当等待该任务时,将重新引发异常,然后catch可以捕获该异常。

但是,异常处理中的这种“间接”意味着在最初引发异常时,IDE确实有些奇怪。据其所知,代码中没有catch会捕获它,因此这就是它中断并显示异常的原因。它不知道编译器生成的代码会捕获它。您可以tell the IDE not to worry about uncaught exceptions