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)
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; }
}