/// <summary> /// Stand-in replacement for HttpClient.GetStringAsync that can report download progress. /// </summary> /// <param name="client">HttpClient instance</param> /// <param name="url">Url of where to download the stream from</param> /// <param name="progessReporter">Progress reporter to track progress of the download operation</param> /// <returns>String result of the GET request</returns> public static async Task <string> DownloadStringWithProgressAsync(this HttpClient client, string url, IProgress <DownloadProgressArgs> progessReporter) { if (client == null) { throw new ArgumentNullException(nameof(client), "HttpClient was null"); } if (string.IsNullOrEmpty(url)) { throw new ArgumentNullException(nameof(url), "You must set a URL for the API endpoint"); } if (progessReporter == null) { throw new ArgumentNullException(nameof(progessReporter), "ProgressReporter was null"); } try { client.DefaultRequestHeaders.ExpectContinue = false; using (var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead)) using (var stream = await response.Content.ReadAsStreamAsync()) using (var memStream = new MemoryStream()) { int receivedBytes = 0; var totalBytes = Convert.ToInt32(response.Content.Headers.ContentLength); while (true) { var buffer = new byte[4096]; int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length); //write the current loop's bytes into the MemoryStream that will be returned await memStream.WriteAsync(buffer, 0, bytesRead); if (bytesRead == 0) { break; } receivedBytes += bytesRead; var args = new DownloadProgressArgs(receivedBytes, totalBytes); progessReporter.Report(args); } memStream.Position = 0; var stringContent = new StreamReader(memStream); return(stringContent.ReadToEnd()); } } finally { client.Dispose(); } }
private void Downloader_ProgressChanged(object sender, DownloadProgressArgs e) { this.Dispatcher.Invoke(new Action(() => { this.Progress.Value = e.Progress; this.Speed.Text = string.Format("{0}KB/S", e.Speed / 1024); //this.Segments.ItemsSource = e.Segments.Select(p => new SegmentViewModel(p)); })); }
public static async Task <(ArraySegment <byte>, HttpResponseMessage)> DownloadBytesWithProgressAsync ( this HttpClient self, Uri uri, IProgress <DownloadProgressArgs> progress, CancellationToken cts = default ) { HttpResponseMessage resp = await self.SendAsync ( new HttpRequestMessage { Version = self.DefaultRequestVersion, Method = HttpMethod.Get, RequestUri = uri }, HttpCompletionOption.ResponseHeadersRead, cts ).ConfigureAwait(false); Debug.Assert(resp is not null); resp.EnsureSuccessStatusCode(); HttpContent content = resp.Content; await using Stream stream = await content.ReadAsStreamAsync(cts).ConfigureAwait(false); int dl_size = content.Headers.ContentLength is long len ? (int)len : 65536; byte[] pool_buffer = ArrayPool <byte> .Shared.Rent(65536); Memory <byte> buf = pool_buffer; var memory = new MemoryStream(dl_size); var args = new DownloadProgressArgs { TotalBytes = (int?)content.Headers.ContentLength, }; progress.Report(args); try { while (true) { cts.ThrowIfCancellationRequested(); int read = await stream.ReadAsync(buf, cts).ConfigureAwait(false); await memory.WriteAsync(buf[..read], cts).ConfigureAwait(false);
/// <summary> /// Helper method to POST binary image data to an API endpoint that expects the data to be accompanied by a parameter /// </summary> /// <param name="client">HttpClient instance</param> /// <param name="imageFile">Valie StorageFile of the image</param> /// <param name="url">The API's http or https endpoint</param> /// <param name="progessReporter">Progress reporter to track progress of the download operation</param> /// <param name="parameterName">The name of the parameter the API expects the image data in</param> /// <returns></returns> public static async Task <string> SendImageDataWithDownloadProgressAsync(this HttpClient client, StorageFile imageFile, string url, string parameterName, IProgress <DownloadProgressArgs> progessReporter) { if (client == null) { throw new ArgumentNullException(nameof(client), "HttpClient was null"); } if (string.IsNullOrEmpty(url)) { throw new ArgumentNullException(nameof(url), "You must set a URL for the the HttpClient"); } if (imageFile == null) { throw new ArgumentNullException(nameof(imageFile), "You must have a valid StorageFile for this method to work"); } if (string.IsNullOrEmpty(parameterName)) { throw new ArgumentNullException(nameof(parameterName), "You must set a parameter name for the image data"); } if (progessReporter == null) { throw new ArgumentNullException(nameof(progessReporter), "ProgressReporter was null"); } try { client.DefaultRequestHeaders.ExpectContinue = false; byte[] fileBytes; using (var fileStream = await imageFile.OpenStreamForReadAsync()) { var binaryReader = new BinaryReader(fileStream); fileBytes = binaryReader.ReadBytes((int)fileStream.Length); } var multipartContent = new MultipartFormDataContent(); multipartContent.Add(new ByteArrayContent(fileBytes), parameterName); using (var response = await client.PostAsync(new Uri(url), multipartContent)) using (var stream = await response.Content.ReadAsStreamAsync()) using (var memStream = new MemoryStream()) { int receivedBytes = 0; var totalBytes = Convert.ToInt32(response.Content.Headers.ContentLength); while (true) { var buffer = new byte[4096]; int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length); //write the current loop's bytes into the MemoryStream that will be returned await memStream.WriteAsync(buffer, 0, bytesRead); if (bytesRead == 0) { break; } receivedBytes += bytesRead; var args = new DownloadProgressArgs(receivedBytes, receivedBytes); progessReporter.Report(args); Debug.WriteLine($"Progress: {receivedBytes} of {totalBytes} bytes read"); } memStream.Position = 0; var stringContent = new StreamReader(memStream); return(stringContent.ReadToEnd()); } } finally { client.Dispose(); } }
//This is the event handler to update your UI of progress (there is no need to use UI Dispatcher) private void Reporter_ProgressChanged(object sender, DownloadProgressArgs e) { DownloadProgress = e.PercentComplete; IsBusyMessage = $"downloading {e.PercentComplete.ToString("N2")}%"; }
/// <summary> /// Makes a POST request to an endpoint with image data that reports upload progress, with cancellation support. /// </summary> /// <param name="client">HttpClient instance</param> /// <param name="imageFilePath">Url of where to download the stream from</param> /// <param name="apiUrl">Endpoint URL</param> /// <param name="parameterName">POST request parameter name</param> /// <param name="progessReporter">Args for reporting progress of the download operation</param> /// <param name="token">Cancellation token</param> /// <returns>String content of the GET request result</returns> public static async Task <string> SendImageDataWithDownloadProgressAsync(this HttpClient client, string imageFilePath, string apiUrl, string parameterName, IProgress <DownloadProgressArgs> progessReporter, CancellationToken token) { if (client == null) { throw new ArgumentNullException(nameof(client), "The HttpClient was null. You must use a valid HttpClient instance to use this extension method."); } if (string.IsNullOrEmpty(apiUrl)) { throw new ArgumentNullException(nameof(apiUrl), "You must set a URL for the API endpoint"); } if (imageFilePath == null) { throw new ArgumentNullException(nameof(imageFilePath), "You must have a valid file path"); } if (string.IsNullOrEmpty(parameterName)) { throw new ArgumentNullException(nameof(parameterName), "You must set a parameter name for the image data"); } if (progessReporter == null) { throw new ArgumentNullException(nameof(progessReporter), "ProgressReporter was null"); } client.DefaultRequestHeaders.ExpectContinue = false; var fileBytes = File.ReadAllBytes(imageFilePath); var multipartContent = new MultipartFormDataContent(); multipartContent.Add(new ByteArrayContent(fileBytes), parameterName); using (var response = await client.PostAsync(new Uri(apiUrl), multipartContent, token)) { //Important - this makes it possible to rewind and re-read the stream await response.Content.LoadIntoBufferAsync(); using (var stream = await response.Content.ReadAsStreamAsync()) { var receivedBytes = 0; var totalBytes = Convert.ToInt32(response.Content.Headers.ContentLength); while (true) { var buffer = new byte[4096]; var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, token); if (bytesRead == 0) { break; } receivedBytes += bytesRead; var args = new DownloadProgressArgs(receivedBytes, receivedBytes); progessReporter.Report(args); Debug.WriteLine($"Progress: {receivedBytes} of {totalBytes} bytes read"); } stream.Position = 0; string result; using (var stringContent = new StreamReader(stream)) { result = await stringContent.ReadToEndAsync(); } return(result); } } }