0

How would you get the current progress as a interger for example when downloading a file? I've been trying to implementing it into the code below with no luck at all

public static async Task HttpDownload(string url, string OutputLocation)
{
     using (HttpClient client = new HttpClient())       
     using (var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
     {
            var contentLength = response.Content.Headers.ContentLength;
            using (Stream streamToReadFrom = await response.Content.ReadAsStreamAsync())
            {
                   string fileToWriteTo = OutputLocation;
                   using (Stream streamToWriteTo = File.Open(fileToWriteTo, FileMode.Create))
                   {
                         await streamToReadFrom.CopyToAsync(streamToWriteTo);
                   }
            }
     }
}

I've tried things like Progress<T>, but it i could never covert it to a usage value

(Edit, I found something thats actually works for me, Progress bar with HttpClient)

  • You'll find a CopyToAsync method with progress reporting in the duplicate question. See also the DownloadAsync method in [this answer](https://stackoverflow.com/a/46497896/1136211). – Clemens Jan 05 '23 at 11:19

1 Answers1

0

I wrote my own method to achieve this. Its complettely stream based. So almost no load on your system memory. But feel free to test it out.

public static async Task<T> DownloadAsync<T>(
            this HttpClient client,
            Uri requestUri,
            Func<HttpResponseMessage, T> destinationStreamFactory,
            IProgress<HttpDownloadProgress> progress = null,
            CancellationToken cancellationToken = default)
            where T : Stream
        {
            // Get the http headers first to examine the content length
            using (var response = await client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken))
            {
                var contentLength = response.Content.Headers.ContentLength;
                using (var download = await response.Content.ReadAsStreamAsync())
                {
                    var destinationStream = destinationStreamFactory(response);

                    // Ignore progress reporting when no progress reporter was 
                    // passed or when the content length is unknown
                    if (progress == null)
                    {
                        await download.CopyToAsync(destinationStream, 81920, cancellationToken);
                        return destinationStream;
                    }

                    // Convert absolute progress (bytes downloaded) into relative progress (0% - 100%)
                    var relativeProgress = new Progress<long>(totalBytes => progress.Report(
                        new HttpDownloadProgress()
                        {
                            ContentLength = contentLength ?? 0,
                            RelativeProgress = contentLength.HasValue ? Convert.ToInt32(100 * (float)totalBytes / contentLength.Value) : 0,
                            ReadBytes = totalBytes
                        }));
                    // Use extension method to report progress while downloading
                    await download.CopyToAsync(destinationStream, 81920, relativeProgress, cancellationToken);
                    progress.Report(new HttpDownloadProgress()
                    {
                        ContentLength = contentLength ?? 0,
                        RelativeProgress = 1,
                        ReadBytes = contentLength ?? 0 
                    });
                    
                    return destinationStream;
                }
            }

Example:

 var downloadProgress = new Progress<HttpDownloadProgress>(
                    f =>
                    {
                        var readMbs = f.ReadBytes / 1024 / 1024;
                        var contentMbs = f.ContentLength / 1024 / 1024;
                        Progress = f.RelativeProgress;
                        Message = $"Downloading {pluginVersion.PluginName} ({readMbs}MB/{contentMbs}MB)";
                    });

using (var fileStream = await client.DownloadAsync(
                           serviceEndPoint,
                           response => CreateFileStream(response, outputPath),
                           downloadProgress,
                           token))
{
    Console.WriteLine($"File name {fileStream.Name}";
}

with the FileStreamFactory, which creates the output folder and a filestream with the extracted file name of the httpreponse:

private FileStream CreateFileStream(HttpResponseMessage response, string outputPath)
        {
            // get the actual content stream
            var fileName = response.Content.Headers.ContentDisposition?.FileName;
            if (fileName == null)
            {
                throw new InvalidOperationException("No filename available");
            }

            var outputFile = Path.Combine(outputPath, fileName);
            var folder = Directory.GetParent(outputFile)?.FullName;
            if (folder != null && !Directory.Exists(folder))
            {
                Directory.CreateDirectory(folder);
            }
            else if (File.Exists(outputFile))
            {
                File.Delete(outputFile);
            }

            Console.WriteLine($"Downloading file to '{outputFile} ...");
            return File.Open(outputFile, FileMode.Create);
        }

public class HttpDownloadProgress
{
    public int RelativeProgress { get; set; }
    public long ContentLength { get; set; }
    public long ReadBytes { get; set; }
}
howardButcher
  • 331
  • 1
  • 9