我返回大量的DataTable行,迭代它们并将每行的值推送到webservice,然后返回响应代码(字符串)。如果Web服务中发生任何错误,整个过程将停止并显示错误:
Protected Sub DoStuff(sender As Object, e As EventArgs) Handles lnk_orderCards.Click
Dim dt as DataTable = GetDataBaseData()
For each dr as DataRow in dt.Rows()
Dim f as String = dr.Item("firstname").ToString()
Dim m as String = dr.Item("middleName").ToString()
Dim s as String = dr.Item("surname").ToString()
Dim err as String = String.Empty
Dim result as String = XYZService.DoIt(f, m, s)
Select Case result
Case "ok"
' OK - allow For Loop Next '
Case "e"
err = "Some error"
Case "e2"
err = "Another error"
End Select
If Not String.IsNullOrWhiteSpace(err) Then
ShowError(err)
Exit Sub
End If
Next
XYZService.Complete()
ltl_status.Text = "Success!"
End Sub
我认为以上是Async方法的一个很好的候选者,特别是如果数据表有1000行,因为每个webservice请求可以并行发送。但是,从MSDN中我找不到足够的示例来说明如何最好地实现Async。
有人可以推荐更彻底的方法吗?我已阅读MSDN关于Task.WaitAll
和Task.Factory.StartNew
的内容,但这些示例并不简单。如果使用Task.WaitAll
like this,如果一个(或多个)任务失败,如何停止流程?
重要的是,所有任务在调用XYZService.Complete()
之前都会返回成功。
基于Stephen的输入的最终代码
Protected Async Sub DoStuff(sender As Object, e As EventArgs) Handles lnk_orderCards.Click
Dim cts As New CancellationTokenSource
Dim dt As DataTable = GetDataBaseData()
Dim rows As IEnumerable(Of Task(Of String)) = (From dr As DataRow In dt.Rows Select DoServiceCall(cts, dr))
Dim results() As String = Await Task.WhenAll(rows)
Dim errors As List(Of String) = (From s As String In results Where s <> String.Empty).ToList()
If errors.Count > 0 Then
ShowError(String.Join("<br/>", errors))
Exit Sub
Else
Console.WriteLine("Success")
End If
End Sub
Protected Async Function DoServiceCall(t As CancellationTokenSource, dr As DataRow) As Task(Of String)
If t.IsCancellationRequested Then
t.Token.ThrowIfCancellationRequested()
End If
Dim f As String = dr.Item("firstname").ToString()
Dim m As String = dr.Item("middleName").ToString()
Dim s As String = dr.Item("surname").ToString()
Dim returnResult As XYZService.ServiceReturnResult = Await XYZService.DoItAsync(f, s, s)
Select Case returnResult.return
Case "ok"
' OK - allow For Loop Next '
Case Else
t.Cancel(False)
Throw New Exception("Web service error: " & returnResult.return)
End Select
Return returnResult.return
End Function
答案 0 :(得分:2)
最简单的解决方案是使用Task.WhenAll
。具体来说,您可以将每个项目(LINQ的Select
)投影到Task (of T)
,然后执行Await Task.WhenAll
。
但是,这种简单的方法将同时执行所有请求,并且如果其中一个请求失败,则不会停止其他请求。这有点复杂;我建议使用CancellationTokenSource
来表示“紧急停止”,每个请求都会收到CancellationToken
,如果失败则取消源。
请勿使用Task.Run
或更差的表兄StartNew
。由于您的操作本质上是异步的(I / O绑定的网络请求),因此您需要异步并发(Task.WhenAll
),而不是并行并发(StartNew
)。