1

I need to communicate with a REST service.

For some reasons, I have to use a POST request to obtain JSON data from that service. (I think it should use a GET request but this is not under my control and I can't change it...)

The response for one request is around 25-30 MB. Since the response is big I decided to use the WebClient and the UploadStringAsync method.

private string jsonResult = "";

void test()
{
    string credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(username + ":" + passowrd));  
    using (System.Net.WebClient client = new System.Net.WebClient())
    {
        client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
        client.UploadProgressChanged += new UploadProgressChangedEventHandler(client_UploadProgressHandler);
        client.UploadStringCompleted += new UploadStringCompletedEventHandler(client_UploadStringCompletedHandler);                
        client.Headers.Add("Authorization", "Basic " + credentials);
        client.Encoding = System.Text.Encoding.UTF8;
        Uri uri = new Uri(https://demoapi.org/stuff/prod/0);

        client.UploadStringAsync(uri, "POST", "");
    }
}

private void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
    Console.WriteLine("DOWNLOAD_PROGRESS!");
    Console.WriteLine("Status {0} of {1} bytes. {2} % complete", e.BytesReceived, e.TotalBytesToReceive, e.ProgressPercentage);
}

private static void client_UploadProgressHandler(object sender, UploadProgressChangedEventArgs e)
{
    Console.WriteLine("UPLOAD_PROGRESS!");
    Console.WriteLine("Status {0} of {1} bytes. {2} % complete, {3} of {4} bytes. {5} % complete", e.BytesReceived, e.TotalBytesToReceive, e.ProgressPercentage, e.BytesSent, e.TotalBytesToSend, e.ProgressPercentage);
}

private void client_UploadStringCompletedHandler(Object sender, UploadStringCompletedEventArgs e)
{
    Console.WriteLine("UPLOAD_COMPLETED!");
    jsonResult = e.Result;
}

With the code above, the console shows many times the message UPLOAD_PROGRESS! and once the message UPLOAD_COMPLETED! However, I don't see the message DOWNLOAD_PROGRESS!

UPLOAD_PROGRESS!
UPLOAD_PROGRESS!
....    
UPLOAD_PROGRESS!
UPLOAD_COMPLETED!

Here are my questions:

1) Can I (really) subscribe to the "UploadProgressChanged" Event with the webclient.UploadStringAsync method ?

The Microsoft documentation does not says that the UploadProgressChanged is available for UploadStringAsync but anyhow it seems to be working with the code above.

https://learn.microsoft.com/en-us/dotnet/api/system.net.webclient.uploadprogresschanged?view=netframework-4.7.2

https://learn.microsoft.com/en-us/dotnet/api/system.net.webclient.uploadstringasync?view=netframework-4.7.2

I also looked at the Microsoft referencesource but I don't fully understand it. The delegate 'UploadProgressChanged' does not seem to be present in the UploadStringAsync method.

https://referencesource.microsoft.com/#System/net/System/Net/webclient.cs,d15a560fedc713da,references

So, I'm wondering if it's correct to use "UploadProgressChanged" with the webclient.UploadStringAsync.

2) Can I subscribe to the "DownloadProgressChanged" event with the webclient.UploadStringAsync method ?

3) As my understanding, the webclient is using a WebRequest and WebResponse under the hood. Is it possible to get the progress of both requests ?

I'm asking this because sometimes the body of the request is big and sometimes the reponse is big.

4) If the DownloadProgressChangedEvent is not available, then how can I report the progress of the WebResponse part of the "UploadStringAsync" POST request ?

Thanks

2
  • Your code above does an upload so it cannot receive a DownloadProgressChanged event. The rule is all a Download or Upload Async methods raise the corresponding Download or Upload progress changed events. Non async methods don't raise progress events. If you want access to the underlying WebRequest, just create a class that derive from WebClient and override the protected virtual GetWebRequest(Uri address) method. Commented Apr 9, 2019 at 10:18
  • OK, I understand that Upload methods are raising only Upload events. However, the documentation don't say anything about ProgressChanged for UploadStringAsync. Can I be sure that Progress Change is called for UploadStringAsync ? I also don`t see the delegate/callback in the referencesource code. It seems to be working with the code above but I don't understand why the documentation and the code don't mention or use it.. PS: Can you post the answer below and I will give you the bounty points. Commented Apr 10, 2019 at 14:33

1 Answer 1

1
+50

Your code above does an upload so it cannot receive a DownloadProgressChanged event.

The rule is all a Download or Upload Async methods raise the corresponding Download or Upload progress changed events. Under the scene, UploadStringAsync is using the same code that UploadDataAsync is using (because a string is an array of bytes modulo the character encoding).

Non-async methods don't raise progress events.

If you want access to the underlying WebRequest, just create a class that derive from WebClient and override the protected virtual GetWebRequest(Uri address) method, like this:

public class MyWebClient : WebClient
{
    protected override WebRequest GetWebRequest(Uri address)
    {
        var request = base.GetWebRequest(address);
        // do something with the request
        // BTW, this is how you can change timeouts or use cookies
        return request;
    }
}

Note you can also use the more modern HttpClient class (which is fully cross platform, frameworks, etc.) instead of WebClient.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.