跟踪HttpWebRequest和HttpWebResponse的进度

时间:2014-01-08 10:47:08

标签: json vb.net httprequest httpresponse getjson

我正在使用发送HTTP请求并获得各自答案的Sharefile API。它们是通过URL制作的,并始终使用相同的功能。在这里。

Private Function InvokeShareFileOperation(ByVal requestUrl As String) As JObject

    Dim request As HttpWebRequest = WebRequest.Create(requestUrl)
    Dim response As HttpWebResponse = request.GetResponse()

    Dim reader As StreamReader = New StreamReader(response.GetResponseStream())

    Dim json As String = reader.ReadToEnd()
    response.Close()
    Return JObject.Parse(json)

End Function

由于某些操作有点长,我需要以某种方式跟踪他们正在进行的进度并且不知道如何操作。后来我打算使用这个进度并从中创建一个进度条。

(编辑) 顺便说一句,它是占用大部分时间的第二个代码行(下面),即跟踪操作。

Dim response As HttpWebResponse = request.GetResponse()

5 个答案:

答案 0 :(得分:4)

编辑:我认为您无法以任何准确的方式衡量进度,因为大部分操作似乎依赖于处理请求的远程服务器。 GetResponse()处理设置DNS,连接,发送和等待远程服务器,这完全不在您手中。只有返回内容长度标头,才能读取响应流。我个人最初会将进度显示为20%,GetResponse返回时显示为60%,如果您在下载前有内容长度,则可以逐步显示最后40%,或者在读完响应流后一次性完成。< / p>

作为Web请求,您可以先查找内容长度,然后使用缓冲区而不是ReadToEnd()读取响应流。这允许您在下载响应时计算进度并触发通知。

Dim request As HttpWebRequest = WebRequest.Create(requestUrl)

Using response As HttpWebResponse = request.GetResponse()
  Dim contentLength As Long = response.ContentLength
  Dim bytesReceived As Long
  Dim bufferLength as Integer = 8192
  Dim buffer(bufferLength) As Char
  Dim sb As New StringBuilder

  Using reader As StreamReader = New StreamReader(response.GetResponseStream())
    Do
      Dim bufferedCount As Integer = reader.Read(buffer, 0, bufferLength)
      sb.Append(buffer, 0, bufferedCount)
      bytesReceived += bufferedCount
      Console.WriteLine(bytesReceived / contentLength * 100 & "%")
    Loop While bytesReceived < contentLength
  End Using

  Return JObject.Parse(sb.ToString)
End Using

显然,您可以将Console.WriteLine替换为进度更新功能或调用SignalR中心来更新网页,您可以尝试使用缓冲区大小来查看哪种方式最适合您。

答案 1 :(得分:3)

首先,我们必须找出什么在放缓。在调用GetResponse()之前不会发送请求,因此服务器处理可能需要一些时间。下载也需要一些时间。如果响应很小(相对于连接速度),你不能做太多(如果服务器是你的,你可以,但我们将专注于客户端),因为你无法从服务器获得进展。如果响应很大,并且您想跟踪下载,则只有拥有Content-Length标题才能执行此操作。要获得只有标头,服务器必须支持HEAD请求方法。所以这是代码:

Imports System
Imports System.Net
Imports System.IO
Imports System.Text
Imports System.Threading
Imports Microsoft.VisualBasic

Public Class Form1

    Private Function InvokeShareFileOperation(ByVal requestUrl As String) As JObject
        HTTPWebRequest_GetResponse.Main(requestUrl)
        ProgressBar1.Value = 0
        Dim result As String
        Do
            Try
                ProgressBar1.Value = HTTPWebRequest_GetResponse.progress
            Catch ex As ArgumentOutOfRangeException
                ProgressBar1.Style = ProgressBarStyle.Marquee
            End Try
            If HTTPWebRequest_GetResponse.done = True Then
                result = HTTPWebRequest_GetResponse.response
                ProgressBar1.Style = ProgressBarStyle.Continuous
                ProgressBar1.Value=100
                Debug.WriteLine(result)
                Return JObject.Parse(result)
                Exit Do
            End If
        Loop
    End Function

End Class


Public Class RequestState
    ' This class stores the State of the request. 
    Private BUFFER_SIZE As Integer = 1024
    Public requestData As StringBuilder
    Public BufferRead() As Byte
    Public request As HttpWebRequest
    Public response As HttpWebResponse
    Public streamResponse As Stream

    Public Sub New()
        BufferRead = New Byte(BUFFER_SIZE) {}
        requestData = New StringBuilder("")
        request = Nothing
        streamResponse = Nothing
    End Sub 'New 
End Class 'RequestState


Class HTTPWebRequest_GetResponse

    Private BUFFER_SIZE As Integer = 1024
    Public Shared response As String
    Public Shared done As Boolean = False
    Public Shared length As Long = 1
    Public Shared progress As Integer
    Public Shared myHttpWebRequest As HttpWebRequest
    Public Shared myRequestState As New RequestState()

    Shared Sub Main(url As String)

        Try
            Dim headRequest As HttpWebRequest = WebRequest.Create(url)
            headRequest.Method = "HEAD"
            Dim headResponse As HttpWebResponse = headRequest.GetResponse
            length = headResponse.ContentLength
            Debug.WriteLine(length)
            headResponse.Close()
            ' Create a HttpWebrequest object to the desired URL.  
            myHttpWebRequest = WebRequest.Create(url)

            ' Create an instance of the RequestState and assign the previous myHttpWebRequest 
            ' object to its request field.   

            myRequestState.request = myHttpWebRequest
            'Dim myResponse As New HTTPWebRequest_GetResponse()

            ' Start the asynchronous request. 
            Dim result As IAsyncResult = CType(myHttpWebRequest.BeginGetResponse(New AsyncCallback(AddressOf RespCallback), myRequestState), IAsyncResult)

        Catch e As WebException
            Debug.WriteLine("Main Exception raised!")
            Debug.WriteLine("Message: " + e.Message)
            Debug.WriteLine("Status: " + e.Status)
        Catch e As Exception
            Debug.WriteLine("Main Exception raised!")
            Debug.WriteLine("Source : " + e.Source)
            Debug.WriteLine("Message : " + e.Message)
        End Try
    End Sub 'Main

    Private Shared Sub RespCallback(asynchronousResult As IAsyncResult)
        Debug.WriteLine("RespCallBack entered")
        Try
            ' State of request is asynchronous. 
            Dim myRequestState As RequestState = CType(asynchronousResult.AsyncState, RequestState)
            Dim myHttpWebRequest As HttpWebRequest = myRequestState.request
            myRequestState.response = CType(myHttpWebRequest.EndGetResponse(asynchronousResult), HttpWebResponse)

            ' Read the response into a Stream object. 
            Dim responseStream As Stream = myRequestState.response.GetResponseStream()
            myRequestState.streamResponse = responseStream

            ' Begin the Reading of the contents of the HTML page. 
            Dim asynchronousInputRead As IAsyncResult = responseStream.BeginRead(myRequestState.BufferRead, 0, 1024, New AsyncCallback(AddressOf ReadCallBack), myRequestState)
            Return
        Catch e As WebException
            Debug.WriteLine("RespCallback Exception raised!")
            Debug.WriteLine("Message: " + e.Message)
            Debug.WriteLine("Status: " + e.Status)
        Catch e As Exception
            Debug.WriteLine("RespCallback Exception raised!")
            Debug.WriteLine("Source : " + e.Source)
            Debug.WriteLine("Message : " + e.Message)
        End Try
    End Sub 'RespCallback

    Private Shared Sub ReadCallBack(asyncResult As IAsyncResult)
        Debug.WriteLine("ReadCallBack entered")
        Try

            Dim myRequestState As RequestState = CType(asyncResult.AsyncState, RequestState)
            Dim responseStream As Stream = myRequestState.streamResponse
            Dim read As Integer = responseStream.EndRead(asyncResult)
            ' Read the HTML page. 
            If read > 0 Then
                myRequestState.requestData.Append(Encoding.ASCII.GetString(myRequestState.BufferRead, 0, read))
                If length = -1 Or length = 0 Then
                    progress = -1
                Else
                    progress = myRequestState.BufferRead.Length * 100 / length
                    Debug.WriteLine(progress)
                End If
                Dim asynchronousResult As IAsyncResult = responseStream.BeginRead(myRequestState.BufferRead, 0, 1024, New AsyncCallback(AddressOf ReadCallBack), myRequestState)

            Else
                If myRequestState.BufferRead.Length > 1 Then
                    Dim fullResponse As String = myRequestState.requestData.ToString
                    response = fullResponse.Substring(0, fullResponse.IndexOf("</body>")).Substring(fullResponse.IndexOf(">", fullResponse.IndexOf("<body")) + 2) 'Returns only body
                    ' Release the HttpWebResponse resource.
                    myRequestState.response.Close()
                    done = True
                    Debug.WriteLine(done)
                End If

                responseStream.Close()
            End If

        Catch e As WebException
            Debug.WriteLine("ReadCallBack Exception raised!")
            Debug.WriteLine("Message: " + e.Message)
            Debug.WriteLine("Status: " + e.Status)
        Catch e As Exception
            Debug.WriteLine("ReadCallBack Exception raised!")
            Debug.WriteLine("Source : " + e.Source)
            Debug.WriteLine("Message : " + e.Message)
        End Try
    End Sub 'ReadCallBack 
End Class 'HttpWebRequest_BeginGetResponse

我从http://msdn.microsoft.com/en-us/library/debx8sh9(v=vs.110).aspx获取代码并更改了它。

编辑:代码现在只返回正文,响应已关闭。

EDIT2:正如@ Geezer68所说,它不是100%准确,但可以向用户显示进度。

答案 2 :(得分:2)

我很确定你想要的是reader.BaseStream.Length所以你可以在阅读之前知道它的长度。 (至少我这样做了,所以我试过了)但是它向NotSupportedException投了This stream does not support seek operations消息。所以我用Google搜索StreamReader + This stream...并找到了这个SO链接:

Error “This stream does not support seek operations” in C#

所以简短的回答是:这是不可能的。

答案 3 :(得分:1)

也许一个简单的秒表是一种开始的方式?

    Dim timer As System.Diagnostics.Stopwatch = New Stopwatch()

    Dim request As HttpWebRequest = WebRequest.Create(requestUrl)

    timer.Start()
    Dim response As HttpWebResponse = request.GetResponse()
    timer.Stop()

    Dim reader As StreamReader = New StreamReader(response.GetResponseStream())
    Dim json As String = reader.ReadToEnd()
    response.Close()

    Label1.Text = "Secs:" & timer.Elapsed.ToString()

答案 4 :(得分:0)

这是Microsoft示例的链接 在此处设置缓冲区大小并在响应对象上回调 https://msdn.microsoft.com/en-us/library/86wf6409%28v=vs.110%29.aspx