Bug 40988 - No way to calculate download progress in System.Net.Http.HttpClient
Summary: No way to calculate download progress in System.Net.Http.HttpClient
Status: RESOLVED FEATURE
Alias: None
Product: Class Libraries
Classification: Mono
Component: System.Net.Http ()
Version: unspecified
Hardware: PC Windows
: --- normal
Target Milestone: Untriaged
Assignee: Marek Safar
URL:
Depends on:
Blocks:
 
Reported: 2016-05-10 11:35 UTC by Akash Kava
Modified: 2016-05-25 07:39 UTC (History)
4 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FEATURE

Description Akash Kava 2016-05-10 11:35:21 UTC
My file is delivered from CDN and it successfully returns content-length header. So I expect to use it to calculate progress.

Following does not work as expected, 

using(var hc = new HttpClient()){

   // this line waits for entire download to finish....
   var r = await hc.GetAsync("http://....url..for..big..download..file");

   var total = r.Content.Headers.ContentLength.GetOrDefaultValue();

   int count = 0;
   int progress = 0;

   using(var s = r.Content.ReadAsStreamAsync()){
      var buffer = new byte[51200];
      while((count = await s.ReadAsync(buffer))>0){
         progress += count;

         // I can use this report progress...
         // but by the time I arrive here, all the content is downloaded
         // so progress goes from 0 to 100 within milliseconds
      }
   }
}

Alternative approach also does not work...

using(var hc = new HttpClient()){

   // this is fast
   using(var s = await hc.GetStreamAsync("http://....url..for..big..download..file")){

      // this returns -1, this should return value from content-length
      var total = s.Length;

      int count = 0;
      int progress = 0;

      var buffer = new byte[51200];
      while((count = await s.ReadAsync(buffer))>0){
         progress += count;

         // I can use this report progress...
         // but by the time I arrive here, all the content is downloaded
         // so progress goes from 0 to 100 within milliseconds
      }
   }
}


So two solutions,
1. Either GetAsync should immediately return and let ReadAsStreamAsync should download content progressively
2. stream.Length must return a value from Content's ContentLength if available
Comment 1 Akash Kava 2016-05-10 11:40:52 UTC
I found the workaround, 

using(var hc = new HttpClient()){

   // this line waits for entire download to finish....
   var g = new HttpRequestMessage(HttpMethod.Get, url);
   var h = await c.SendAsync(g, HttpCompletionOption.ResponseHeadersRead);

   var total = r.Content.Headers.ContentLength.GetOrDefaultValue();

   int count = 0;
   int progress = 0;

   using(var s = r.Content.ReadAsStreamAsync()){
      var buffer = new byte[51200];
      while((count = await s.ReadAsync(buffer))>0){
         progress += count;

         // I can use this report progress...
         // but by the time I arrive here, all the content is downloaded
         // so progress goes from 0 to 100 within milliseconds
      }
   }
}
Comment 2 Akash Kava 2016-05-10 11:49:21 UTC
Nope, workaround does not work, now total returns 0.
Comment 3 Marek Habersack 2016-05-19 07:34:12 UTC
I don't see anything Android-specific in this report. Akash, if you can provide a full repro that would be great. Please also check whether the progress reporting code *works* on both .NET and desktop Mono - if it doesn't work there then there's not much we can do.
Comment 4 Akash Kava 2016-05-19 14:44:35 UTC
Work around is working, I checked with .NET , default for HtmlCompletionOption is set to ResponseContentRead instead of ResponseHeadersRead. I think this is not a bug but it is kind of not working as expected.
Comment 5 Marek Safar 2016-05-25 07:39:34 UTC
Code like

using (HttpResponseMessage response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))

is correct approach. The default is the opposite (reading everything) which is what most scenarios want.

Closing, as you got it working as expected. Otherwise, please reopen.