I'm trying to display download progress using HttpClient. For that I use System.Progress<T>
. Code looks like this:
long totalRead = 0L;
var buffer = new byte[1024];
bool isMoreToRead = true;
ulong total = (ulong)response.Content.Headers.ContentLength;
while (isMoreToRead)
{
int read = await stream.ReadAsync(buffer, 0, buffer.Length);
if (read == 0)
isMoreToRead = false;
else
{
var data = new byte[read];
buffer.ToList().CopyTo(0, data, 0, read);
totalRead += read;
progress.Report((int) (totalRead*1d / total * 1d * 100) );
}
}
Assume subscribing looks like this:
var progress = new Progress<int>();
progress.ProgressChanged += (sender, i) => Console.WriteLine(i);
client.Download(file, progress).Wait();
But as a result, progress order is inconsistent, like this: 10, 20, 30, 70, 15, 90, 100, 80.
Is this a default delegate's behaviour, or there's another reason?
Progress<T>.Report
is asynchronous; by that I mean, Report
method will not raise the ProgressChanged
event synchronously before it returns.
Progress<T>
class captures the SynchronizationContext and posts the invocation of ProgressChanged
event to that captured context.
When used in single threaded context like Winforms, Wpf, your code will work as expected.
In a console app, there will not be any SynchronizationContext and thus Progress<T>
posts the invocation to the default SynchronizationContext which delegates to ThreadPool. ThreadPool doesn't guarantee any order, that's the reason you don't see synchronous result.
I believe you're testing this code in Console app or something similar otherwise nothing wrong with your code.
If you need a synchronous version of IProgress<T>
, you have to roll your own.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With