使用ReadAsync发生了类型'System.AggregateException'的异常

时间:2015-12-04 04:55:28

标签: vb.net sockets async-await

背景:我正在使用Visual Basic,VS社区2013.我正在制作Windows窗体应用程序。用例是:用户单击一个按钮。这会弹出一个对话框。然后,TCP客户端连接到远程服务器,并等待从服务器到达的消息。每次收到消息时,对话框上都会显示文本。如果远程端关闭套接字,则应关闭对话框。此外,用户可以单击对话框上的一个按钮,该按钮应关闭套接字并关闭对话框。

我的代码似乎实现了除最后一个要求之外的所有内容。当用户单击按钮关闭对话框时,我会得到通常的异常弹出窗口,其中包含文本:

An exception of type 'System.AggregateException' occurred in mscorlib.dll but was not handled in user code.
Additional information: One or more errors occurred.

选择“中断”表示条件T.Result = 0已突出显示。调试器显示T的值为Id = 1, Status = Faulted {7}, Method = "{null}", Result = "{Not yet computed}"

我的问题是:这个错误意味着什么,我该如何解决?

以下是对话框代码的相关部分。为简洁起见,我省略了函数ShowStatus,除了更新表单上的可视化控件外,它什么也没做。

Imports Microsoft.VisualBasic
Imports System.Net.Sockets
Imports System.Text

Public Class FormMyDialog
    Private gRequest As String
    Private inbuf(10000) As Byte
    Private inoff As Integer
    Private serv As NetworkStream
    Private sock As System.Net.Sockets.TcpClient

    ' the main form calls this when the user clicks a button
    Public Sub Go(request As String)
        gRequest = request
        ShowDialog()
    End Sub

    ' this is the Close button I have placed on the dialog
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        sock.Close()
    End Sub

    Private Sub FormMyDialog_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
        sock = New System.Net.Sockets.TcpClient()
        ShowStatus("Connecting")
        sock.Connect("127.0.0.1", 53000)
        ShowStatus("Connected")

        serv = sock.GetStream()

        Dim outbuf As Byte() = Encoding.ASCII.GetBytes(gRequest + Chr(10))
        serv.Write(outbuf, 0, outbuf.Length)
        serv.Flush()

        inoff = 0
        ReadLoop()
    End Sub

    Private Sub ReadLoop()
        Dim readlen As Integer
        Dim T As Task(Of Integer)
        T = serv.ReadAsync(inbuf, inoff, inbuf.Length - inoff)
        If T.Result = 0 Then
            sock.Close()
            Dim d As MethodNoArgs(Of Object)
            d = AddressOf Me.Close
            Me.Invoke(d)
            Return
        End If

        readlen = T.Result
        inoff = inoff + readlen
        ProcessInbuf()
        T.ContinueWith(Sub() ReadLoop())
    End Sub

    Public Delegate Sub MethodNoArgs(Of T1)()

    Private Sub ProcessInbuf()
        ' (omitted) processing that calls ShowStatus
        ' and updates inbuf and inoff
    End Sub

End Class

1 个答案:

答案 0 :(得分:2)

您已经注意到AggregateException只是发生多个可能异常的包装。

我不完全确定为什么这个函数失败,但它可能是由于代码的奇怪结构造成的。我看到的主要问题是您没有遵循干净的async - await结构。通常情况下,您不需要使用ContinueWith.Result来实现您想要做的事情。

关键是使用await关键字。此关键字基本上包含ContinueWith.Result。这意味着它等待非阻塞,直到异步操作完成并返回结果。

你的代码实际上可以归结为类似的东西:

Private Async Sub ReadLoop()
    Dim readlen As Integer

    Do
        readlen = Await serv.ReadAsync(inbuf, inoff, inbuf.Length - inoff)
        inoff = inoff + readlen
        ProcessInbuf() 
        'maybe this should be async too, to wait until the processing is done
    Loop While readlen > 0

    sock.Close()
    Me.Close()
End Sub

使用Await的另一个好处是它还可以展开AggregateException。您只需要确保正确处理异常,因为Async Sub可能由于异常而终止,并且不会将异常返回给外部类。一旦它通过第一个Await就会发生这种情况。但是你的代码是同一个问题"一旦它通过ContinueWith