Skip to content

Instantly share code, notes, and snippets.

@dalexsoto
Last active April 3, 2024 15:01
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dalexsoto/9fd3c5bdbe9f61a717d47c5843384d11 to your computer and use it in GitHub Desktop.
Save dalexsoto/9fd3c5bdbe9f61a717d47c5843384d11 to your computer and use it in GitHub Desktop.
Add Progress reporting to capabilities to HttpClient

HttpClientProgressExtensions

Add Progress reporting to capabilities to HttpClient

using HttpClientProgress;

A little routine to download a PDF file from the internet.

async Task DownloadFile ()
{
	// for the sake of the example lets add a client definition here
	var client = new HttpClient ();
	var docUrl = "https://pspdfkit.com/downloads/case-study-box.pdf";
	var filePath = Path.Combine (Path.GetTempPath (), "case-study-box.pdf");

	// Setup your progress reporter
	var progress = new Progress<float> ();
	progress.ProgressChanged += Progress_ProgressChanged;

	// Use the provided extension method
 	using (var file = new FileStream (filePath, FileMode.Create, FileAccess.Write, FileShare.None))
		await client.DownloadDataAsync (docUrl, file, progress);
}

void Progress_ProgressChanged (object sender, float progress)
{
	// Do something with your progress
	Console.WriteLine (progress);
}
using System;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace HttpClientProgress {
public static class HttpClientProgressExtensions {
public static async Task DownloadDataAsync (this HttpClient client, string requestUrl, Stream destination, IProgress<float> progress = null, CancellationToken cancellationToken = default (CancellationToken))
{
using (var response = await client.GetAsync (requestUrl, HttpCompletionOption.ResponseHeadersRead)) {
var contentLength = response.Content.Headers.ContentLength;
using (var download = await response.Content.ReadAsStreamAsync ()) {
// no progress... no contentLength... very sad
if (progress is null || !contentLength.HasValue) {
await download.CopyToAsync (destination);
return;
}
// Such progress and contentLength much reporting Wow!
var progressWrapper = new Progress<long> (totalBytes => progress.Report (GetProgressPercentage (totalBytes, contentLength.Value)));
await download.CopyToAsync (destination, 81920, progressWrapper, cancellationToken);
}
}
float GetProgressPercentage (float totalBytes, float currentBytes) => (totalBytes / currentBytes) * 100f;
}
static async Task CopyToAsync (this Stream source, Stream destination, int bufferSize, IProgress<long> progress = null, CancellationToken cancellationToken = default (CancellationToken))
{
if (bufferSize < 0)
throw new ArgumentOutOfRangeException (nameof (bufferSize));
if (source is null)
throw new ArgumentNullException (nameof (source));
if (!source.CanRead)
throw new InvalidOperationException ($"'{nameof (source)}' is not readable.");
if (destination == null)
throw new ArgumentNullException (nameof (destination));
if (!destination.CanWrite)
throw new InvalidOperationException ($"'{nameof (destination)}' is not writable.");
var buffer = new byte[bufferSize];
long totalBytesRead = 0;
int bytesRead;
while ((bytesRead = await source.ReadAsync (buffer, 0, buffer.Length, cancellationToken).ConfigureAwait (false)) != 0) {
await destination.WriteAsync (buffer, 0, bytesRead, cancellationToken).ConfigureAwait (false);
totalBytesRead += bytesRead;
progress?.Report (totalBytesRead);
}
}
}
}
@fgroupindonesia
Copy link

why is the code has an error syntax on the part of :

float GetProgressPercentage (float totalBytes, float currentBytes) => (totalBytes / currentBytes) * 100f;

@ericbrunner
Copy link

Thanks you very much for sharing 👍

@chekete
Copy link

chekete commented Feb 17, 2021

That help a lot

@sn4k3
Copy link

sn4k3 commented Sep 11, 2021

Can the same be done for upload / put requests?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment