Percentage progress on upload and download using the HttpWebRequest class

I am trying to upload and download (in the same request) to the server using HttpWebRequestin C#, and since the data size is significant (considering the network speed), I would like to show the user how far the jobs are and how much is left (not in seconds, but in percent).

I read a few examples trying to implement this, but none of them show a progress bar. They all just use asyncit so as not to block the user interface when loading / downloading it. And they mainly focus on upload / download, and no attempt has them both included in the same request.

Since I use .Net 4 as my target structure, I cannot implement the method asyncmyself. If you want to offer something asynchronous, just use the Begin...methods, not the awaitkeyword! Thanks.

+4
source share
3 answers

You need to know a few things to succeed with this.

Step 0: save the documentation for .NET 4.0:

HttpWebRequest, , GetResponse() : BeginGetResponse() EndGetResponse(). .NET, " IAsyncResult". , , . :

  • Foo() BeginFoo(), IAsyncResult. Foo() , .
  • BeginFoo() AsyncCallback, , , , . ( , , HttpWebRequest).
  • EndFoo() IAsyncResult, BeginFoo() , , Foo().

, , . , " ", , , , . , , BeginFoo(), . :

  • InvokeRequired, . true, , .
  • Invoke(), , .

, , WinForms, Google. , . , . progressBar1, GetWebContent() .

HttpWebRequest _request;
IAsyncResult _responseAsyncResult;

private void GetWebContent() {
    _request = WebRequest.Create("http://www.google.com") as HttpWebRequest;
    _responseAsyncResult = _request.BeginGetResponse(ResponseCallback, null);           
}

GetResponse(). IAsyncResult , ResponseCallback() EndGetResponse(). GetWebContent() , , , . ResponseCallback():

private void ResponseCallback(object state) {
    var response = _request.EndGetResponse(_responseAsyncResult) as HttpWebResponse;
    long contentLength = response.ContentLength;
    if (contentLength == -1) {
        // You'll have to figure this one out.
    }
    Stream responseStream = response.GetResponseStream();
    GetContentWithProgressReporting(responseStream, contentLength);
    response.Close();
}

object AsyncCallback, . EndGetResponse() IAsyncResult, , , . , , , - .

, , , . , , , -1. , , . - , .

, , , :

private byte[] GetContentWithProgressReporting(Stream responseStream, long contentLength) {
    UpdateProgressBar(0);

    // Allocate space for the content
    var data = new byte[contentLength];
    int currentIndex = 0;
    int bytesReceived = 0;
    var buffer = new byte[256];
    do {
        bytesReceived = responseStream.Read(buffer, 0, 256);
        Array.Copy(buffer, 0, data, currentIndex, bytesReceived);
        currentIndex += bytesReceived;

        // Report percentage
        double percentage = (double)currentIndex / contentLength;
        UpdateProgressBar((int)(percentage * 100));
    } while (currentIndex < contentLength);

    UpdateProgressBar(100);
    return data;
}

( ), .

. . . , . , , . , , , .

( , : , , . Stopwatch , .)

, , , -:

private void UpdateProgressBar(int percentage) {
    // If on a worker thread, marshal the call to the UI thread
    if (progressBar1.InvokeRequired) {
        progressBar1.Invoke(new Action<int>(UpdateProgressBar), percentage);
    } else {
        progressBar1.Value = percentage;
    }
}

InvokeRequired true, Invoke(). , . WPF, , , Dispatcher.

. , async . IAsyncResult , . , .

:

  • . .
  • GetResponse(), EndGetResponse().
  • , , , . .
  • , ! , Stream, Length, , . A Stream NotSupportedException , , -1, , , , , , , : " ?"
  • , :
    • .
    • : , , HttpWebRequest.BeginGetRequestStream(), . .
+31

HttpWebRequest.ContentLength HttpWebRequest.SendChunked GetRequestStream, Stream. [Begin] Write. , , . .

0

bytesReceived, responseStream.Read(buffer, 0, 256); , , (do... while) true, , , TCP contentLength.

The only fix that is required is to have another local variable that will act as a battery to track overall progress, for example. totalBytesReceived + = bytesReceived; and use while (totalBytesReceived <contentLength). I tried using currentIndex for this purpose, however it was causing problems (loading kiosks), so a new independent variable was used.

Here is what I ended up using:

    private byte[] GetContentWithProgressReporting(Stream responseStream, long contentLength) {
UpdateProgressBar(0);

// Allocate space for the content
var data = new byte[contentLength];
int currentIndex = 0;
int bytesReceived = 0;
int totalBytesReceived = 0;
var buffer = new byte[256];
do {
    bytesReceived = responseStream.Read(buffer, 0, 256);
    Array.Copy(buffer, 0, data, currentIndex, bytesReceived);
    currentIndex += bytesReceived;
    totalBytesReceived += bytesReceived;

    // Report percentage
    double percentage = (double)currentIndex / contentLength;
    UpdateProgressBar((int)(percentage * 100));



} while (totalBytesReceived < contentLength);

//DEBUGGING:  MessageBox.Show("GetContentWithProgressReporting Method - Out of loop");
UpdateProgressBar(100);
return data;

}

Also, the code worked very well!

0
source

All Articles