internal byte[] FromReaderToStream(StreamReader sr, Stream destinationStream, ref DownloadMetric metric, ref Stopwatch stopwatch, ref long?length, CancellationToken ct) { //int kb = metric.Speed > Globals.PageSize ? (int)metric.Speed : Globals.PageSize; int kb = 1024 * 65; int toDownload = kb; var buffer = new byte[toDownload]; int bytesRead; while ((bytesRead = sr.BaseStream.Read(buffer, 0, buffer.Length)) > 0) { // Poll on this property if you have to do // other cleanup before throwing. if (ct.IsCancellationRequested) { // Clean up here, then... destinationStream.SetLength(0); destinationStream.Close(); if (destinationStream is FileStream) { var fs = destinationStream as FileStream; if (File.Exists(fs.Name)) { File.Delete(fs.Name); } } ct.ThrowIfCancellationRequested(); } destinationStream.Write(buffer, 0, bytesRead); metric.DownloadedBytes += bytesRead; metric.ElapsedTime = stopwatch.Elapsed; OnDownloading?.Invoke(metric); length -= bytesRead; toDownload = length >= kb ? kb : (int)length; buffer = new byte[toDownload]; } stopwatch.Stop(); DownloadTrace.Invoke("Download finished!"); DownloadTrace.Invoke("Returning results..."); //DownloadCompleted?.Invoke(metric, destinationStream); //stopwatch.Reset(); if (destinationStream is MemoryStream) { return(((MemoryStream)destinationStream).ToArray()); } else { destinationStream.Flush(); destinationStream.Close(); destinationStream.Dispose(); return(null); } }
internal async Task <byte[]> ProcessDownloadAsync(Uri uri, Stream output, CancellationToken ct) { byte[] vs = Array.Empty <byte>(); try { #region Get file size DownloadTrace?.Invoke("Getting file size..."); WebRequest webRequest = WebRequest.Create(uri); webRequest.Method = "HEAD"; Stopwatch watch = new Stopwatch(); DownloadMetric m = new DownloadMetric(); long? bytes; watch.Start(); using (WebResponse webResponse = webRequest.GetResponse()) { bytes = long.Parse(webResponse.Headers.Get("Content-Length")); DownloadTrace?.Invoke($"File size: {bytes.Value.HumanizeBytes(2)}"); m.TotalBytes = bytes.Value; m.ElapsedTime = watch.Elapsed; } /*__________________________________________________________________________________ | | | .NET runtime has a 2GB size limit for objects. | | ---------------------------------------------- | | To adhere to this restriction, this module ONLY allows downloading files | | less than 1GB. If the file is greater than 1GB, call DownloadToFile method | | instead which downloads the file directly to disk or allow this application | | to automatically save the file to disk for you. | | ---------------------------------------------- | | 1 GB = 1,000,000,000 (1 Billion Bytes). | | | *|________________________________________________________________________________|*/ if (bytes == null) { bytes = _maxDowloadSize; } else { if (bytes.Value > _maxDowloadSize) { bytes = _maxDowloadSize; } } #endregion #region Read Content Stream Asynchronously long?l = bytes; DownloadTrace?.Invoke("Download about to begin."); DownloadTrace.Invoke("On your marks..."); HttpWebRequest req = WebRequest.Create(uri) as HttpWebRequest; req.Method = "GET"; req.AddRange(0, bytes.Value); vs = await Task.Run(async() => { // Check if operation is already canceled? ct.ThrowIfCancellationRequested(); using (StreamReader sr = new StreamReader((await req.GetResponseAsync()).GetResponseStream())) { DownloadTrace.Invoke("Download started!"); OnDownloadStart?.Invoke(m); var a = FromReaderToStream(sr, output, ref m, ref watch, ref l, ct); DownloadCompleted?.Invoke(m, null); return(a); } }, ct); #endregion } catch (OperationCanceledException) { string msg = "Download cancelled by user"; DownloadTrace.Invoke(msg); OnError?.Invoke(new DownloadClientException(msg)); } catch (Exception ex) { string msg = "An unexpected error occured."; DownloadTrace?.Invoke(msg); OnError?.Invoke(new DownloadClientException($"{msg}\n\nDownload failed. See inner exception for details.", ex)); } return(vs); }