Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/google-app-engine/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asp.net 将迭代转换为异步_Asp.net_.net_Vb.net_Asynchronous_Asp.net 4.5 - Fatal编程技术网

Asp.net 将迭代转换为异步

Asp.net 将迭代转换为异步,asp.net,.net,vb.net,asynchronous,asp.net-4.5,Asp.net,.net,Vb.net,Asynchronous,Asp.net 4.5,我返回大量DataTable行,对它们进行迭代,并将每行的值推送到webservice,然后webservice返回一个响应代码(字符串)。如果webservice中出现任何错误,整个过程将停止,并显示一个错误: Protected Sub DoStuff(sender As Object, e As EventArgs) Handles lnk_orderCards.Click Dim dt as DataTable = GetDataBaseData() For each d

我返回大量DataTable行,对它们进行迭代,并将每行的值推送到webservice,然后webservice返回一个响应代码(字符串)。如果webservice中出现任何错误,整个过程将停止,并显示一个错误:

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
我认为上述方法是异步方法的一个很好的候选者,特别是如果datatable有1000行,因为每个webservice请求都可以并行发送。然而,在MSDN中,我找不到足够的例子来说明如何最好地实现异步

有人能推荐一种更彻底的方法吗?我已经读过关于
Task.WaitAll
Task.Factory.StartNew
的内容,但示例并不简单。如果使用了
Task.WaitAll
,如果一个(或多个)任务失败,如何停止流程

在调用
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
Protected Async Sub DoStuff(发送方作为对象,e作为事件参数)处理lnk\U医嘱卡。单击
Dim cts作为新的CancellationTokenSource
Dim dt As DataTable=GetDataBaseData()
将行设置为IEnumerable(属于任务(属于字符串))=(从dr设置为dt中的数据行。行选择DoServiceCall(cts,dr))
Dim results()作为字符串=等待任务.WhenAll(行)
Dim errors As List(Of String)=(从s作为结果中的字符串,其中s String.Empty)。ToList()
如果错误。计数>0,则
淋浴错误(String.Join(“
”,错误)) 出口接头 其他的 Console.WriteLine(“成功”) 如果结束 端接头 受保护的异步函数DoServiceCall(t作为CancellationTokenSource,dr作为DataRow)作为任务(字符串) 如果要求t.IsCancellation,则 t、 Token.ThrowIfCancellationRequested() 如果结束 Dim f As String=dr.Item(“firstname”).ToString() Dim m As String=dr.Item(“middleName”).ToString() Dim s As String=dr.Item(“姓氏”).ToString() Dim returnResult作为XYZService.ServiceReturnResult=等待XYZService.DoItAsync(f、s、s) 选择Case returnResult.return 案例“ok” '确定-允许循环下一步' 其他情况 t、 取消(假) 抛出新异常(“Web服务错误:&returnResult.return”) 结束选择 returnResult.Return 端函数
最简单的解决方案是使用
任务。具体来说,您可以将(LINQ的
选择
)每个项目投影到
任务(共T个)
中,然后执行
等待任务

但是,这种简单的方法将并发执行所有请求,并且如果其中一个请求失败,则不会停止其他请求。这有点复杂;我建议使用
CancellationTokenSource
来表示“紧急停止”,每个请求都会收到
CancellationToken
,如果失败,则取消源


不要使用
任务。运行
或其更糟糕的近亲
开始新的
。由于您的操作本质上是异步的(I/O绑定的网络请求),因此您需要异步并发(
Task.WhenAll
),而不是并行并发(
StartNew
)。

async/await不会并行执行任何操作。但是,它将允许GUI在等待时保持响应。如果您想要并行执行,请使用
Task.Factory.StartNew
。然后我读到ASP.Net中的
StartNew
是一个非常糟糕的主意(),并且替代方案没有正确的文档记录,整个过程变得更加混乱……:-/开火然后忘记是个坏主意。如果你并行地启动100个任务并等待它们,那就不是开火&忘记。(这仍然是一个可能的DoS,因为一个请求会产生大量的工作)@DasKrümelmonster这并不完全正确,而
async
本身并不会导致方法神奇地异步执行,在点击第一个
wait
时,代码可能会在不同的同步上下文上运行,从而在不同的线程上运行,您希望将循环代码分解成一个单独的方法。这将引导您找到更好的解决方案。您需要传入
CancellationTokenSource
,并使用异常处理错误,而不是字符串。再次感谢。根据你的评论,我又做了一次修改。我走对了吗?是的。实际上,我会传入
DataRow
,并在
DoServiceCall
方法中执行所有操作。然后,您可以很容易地将foreach循环更改为LINQ
Select
语句。它看起来很不错(但我对VB的理解不太好)。我认为您只需要在
DoServiceCall
方法的开头添加一个取消令牌检查。所谓“检查”,实际上是指
throwifcancellationrequest