2.4Downloading Network Resources
One of the most common application scenarios for HTTP remote requests is downloading network resources and saving them to the local disk, including downloading web page content, images, archives, and installation software. The following example shows how to download the ASP.NET Core runtime:
// Download the ASP.NET Core runtime from the specified URL and save it to the C:\Workspaces\ directory// If no file name is specified, the framework automatically resolves the file name from the download URL, for example: aspnetcore-runtime-8.0.10-win-x64.exevar fileTransferResult = await httpRemoteService.DownloadFileAsync("https://download.visualstudio.microsoft.com/download/pr/a17b907f-8457-45a8-90db-53f2665ee49e/49bccd33593ebceb2847674fe5fd768e/aspnetcore-runtime-8.0.10-win-x64.exe" , @"C:\Workspaces\"); // To specify a file name, set it to C:\Workspaces\aspnetcore-runtime.exeAfter the file download completes, the framework returns a FileTransferResult object with the following properties:
IsSuccess: Whether the transfer completed successfully (booltype). Note: Skipping because the file already exists is also considered a success.RequestUri: The file transfer address (stringtype). For downloads, this is the download address; for uploads, this is the upload address.FilePath: The file's path (stringtype).FileSize: The file's size (alongtype in bytes).ElapsedMilliseconds: The transfer duration (alongtype in milliseconds).StatusCode: The response status (HttpStatusCodetype).
If the local file already exists, an InvalidOperationException will be thrown: System.InvalidOperationException: The destination path 'C:\Workspaces\aspnetcore-runtime-8.0.10-win-x64.exe' already exists.. In this case, you can specify the behavior when the file exists via the fileExistsBehavior parameter:
var fileTransferResult = await httpRemoteService.DownloadFileAsync("https://download.visualstudio.microsoft.com/download/pr/a17b907f-8457-45a8-90db-53f2665ee49e/49bccd33593ebceb2847674fe5fd768e/aspnetcore-runtime-8.0.10-win-x64.exe" , @"C:\Workspaces\" , fileExistsBehavior: FileExistsBehavior.Overwrite); // Overwrite if the file existsThe FileExistsBehavior enum contains the following options:
CreateNew(default): If the file already exists, an exception is thrown; otherwise, a new file is created.Overwrite: Overwrites the existing file.Skip: Keeps the existing file and skips the download operation.
While downloading a file, you can also obtain real-time download progress. The following example shows how to print the download progress:
var fileTransferResult = await httpRemoteService.DownloadFileAsync("https://download.visualstudio.microsoft.com/download/pr/a17b907f-8457-45a8-90db-53f2665ee49e/49bccd33593ebceb2847674fe5fd768e/aspnetcore-runtime-8.0.10-win-x64.exe" , @"C:\Workspaces\" , async progress => { Console.WriteLine(await progress.ToSummaryStringAsync()); // Output a brief progress string } , fileExistsBehavior: FileExistsBehavior.Overwrite);Example console output of download progress (using progress.ToSummaryString()):
Transferred 0.26MB of 10.09MB (2.63% complete, Speed: 3.86MB/s, Time: 0.07s, ETA: 2.55s). File: aspnetcore-runtime-8.0.10-win-x64.exe, Path: C:\Workspaces\aspnetcore-runtime-8.0.10-win-x64.exe.Transferred 10.09MB of 10.09MB (100.00% complete, Speed: 9.99MB/s, Time: 1.01s, ETA: 0.00s). Done! File: aspnetcore-runtime-8.0.10-win-x64.exe, Path: C:\Workspaces\aspnetcore-runtime-8.0.10-win-x64.exe.To display file download progress in real time in the console, the UpdateConsoleProgressAsync() method is recommended. An example follows:
var fileTransferResult = await httpRemoteService.DownloadFileAsync("https://download.visualstudio.microsoft.com/download/pr/a17b907f-8457-45a8-90db-53f2665ee49e/49bccd33593ebceb2847674fe5fd768e/aspnetcore-runtime-8.0.10-win-x64.exe" , @"C:\Workspaces\" , progress => progress.UpdateConsoleProgressAsync() // Update the file transfer progress bar in the console , fileExistsBehavior: FileExistsBehavior.Overwrite);// ✅ Or use the DownloadFileWithConsoleProgressAsync method (with console progress printing) var fileTransferResult = await httpRemoteService.DownloadFileWithConsoleProgressAsync("https://download.visualstudio.microsoft.com/download/pr/a17b907f-8457-45a8-90db-53f2665ee49e/49bccd33593ebceb2847674fe5fd768e/aspnetcore-runtime-8.0.10-win-x64.exe" , @"C:\Workspaces\" , fileExistsBehavior: FileExistsBehavior.Overwrite);After execution, the console displays the following progress information:
File: aspnetcore-runtime-8.0.10-win-x64.exe, Path: C:\Workspaces\aspnetcore-runtime-8.0.10-win-x64.exe[############################## ] 61.35% (6.19MB/10.09MB) Speed: 5.81MB/s, Time: 1.07s, ETA: 0.67s.If you use progress.ToString(), the console output will contain more detailed progress information:
Transfer Progress: File Name: aspnetcore-runtime-8.0.10-win-x64.exe File Path: C:\Workspaces\aspnetcore-runtime-8.0.10-win-x64.exe File Size: 10.09MB Transferred: 0.12MB Percentage Complete: 1.23% Transfer Rate: 2.20MB/s Time Elapsed (s): 0.06 Estimated Time Remaining (s): 4.52Transfer Progress: File Name: aspnetcore-runtime-8.0.10-win-x64.exe File Path: C:\Workspaces\aspnetcore-runtime-8.0.10-win-x64.exe File Size: 10.09MB Transferred: 10.09MB Percentage Complete: 100.00% Transfer Rate: 9.77MB/s Time Elapsed (s): 1.03 Estimated Time Remaining (s): 0.00The type of the progress parameter is FileTransferProgress, which contains the following properties and methods:
-
Properties:
FilePath: The file's path (stringtype).FileName: The file's name (stringtype).FileSize: The file's size (alongtype in bytes).Transferred: The amount of data transferred (alongtype in bytes).PercentageComplete: The percentage of the transfer completed (doubletype).TransferRate: The current transfer rate (adoubletype in bytes/second).TimeElapsed: The duration from the start of the transfer to the present (TimeSpantype).EstimatedTimeRemaining: The estimated remaining transfer time (TimeSpantype).
-
Methods:
ToString(): Outputs a detailed, indented progress string.ToStringAsync(): Outputs a detailed, indented progress string.ToSummaryString(): Outputs a brief progress string.ToSummaryStringAsync(): Outputs a brief progress string.UpdateConsoleProgress(): Updates (prints) the file transfer progress bar in the console.UpdateConsoleProgressAsync(): Updates (prints) the file transfer progress bar in the console.
Downloading Multiple Files in Parallel
The framework natively supports downloading multiple files in parallel. With the ParallelUtility.ForEachAsync utility method, you can easily implement concurrent downloads and automatically enable multi-line progress bar mode — each file occupies two lines (the file header and the progress bar), and all progress bars refresh on the same screen in real time without interfering with each other:
var urls = new[]{ "https://img-s.msn.cn/tenant/amp/entityid/AA296jTM.img?w=640&h=1068&m=6", "https://img-s.msn.cn/tenant/amp/entityid/AA297bnQ.img?w=640&h=1240&m=6&x=236&y=233&s=64&d=64", "https://img-s.msn.cn/tenant/amp/entityid/AA296Rr4.img?w=640&h=821&m=6"};const string saveDir = @"C:\Workspaces\";// Download in parallel; the default maximum concurrency is 4await ParallelUtility.ForEachAsync(urls, async (url, token) => { await _httpRemoteService.DownloadFileWithConsoleProgressAsync(url, saveDir, FileExistsBehavior.Overwrite, cancellationToken: token); });After execution, the console displays the download progress of all files simultaneously, with each file's progress bar refreshing independently:
File: AA296jTM.img, Path: C:\Workspaces\AA296jTM.img[########............] 40.12% (0.05MB/0.12MB) Speed: 1.20MB/s, Time: 42ms, ETA: 58ms.File: AA297bnQ.img, Path: C:\Workspaces\AA297bnQ.img[######..............] 30.05% (0.04MB/0.12MB) Speed: 0.95MB/s, Time: 38ms, ETA: 84ms.File: AA296Rr4.img, Path: C:\Workspaces\AA296Rr4.img[##########..........] 50.33% (0.06MB/0.12MB) Speed: 1.55MB/s, Time: 45ms, ETA: 39ms.After all files finish downloading, the progress bars display the Done! status one by one:
File: AA296jTM.img, Path: C:\Workspaces\AA296jTM.img[####################] 100.00% (0.12MB/0.12MB) Speed: 2.61MB/s, Time: 167ms. Done!File: AA297bnQ.img, Path: C:\Workspaces\AA297bnQ.img[####################] 100.00% (0.12MB/0.12MB) Speed: 1.81MB/s, Time: 203ms. Done!File: AA296Rr4.img, Path: C:\Workspaces\AA296Rr4.img[####################] 100.00% (0.12MB/0.12MB) Speed: 1.61MB/s, Time: 204ms. Done!You can also control the maximum concurrency via the maxDegreeOfParallelism parameter:
await ParallelUtility.ForEachAsync(urls, async (url, token) => { await _httpRemoteService.DownloadFileWithConsoleProgressAsync(url, saveDir, FileExistsBehavior.Overwrite, cancellationToken: token); }, maxDegreeOfParallelism: 2); // Download at most 2 files at the same timeIn addition to the approaches above, the following methods are also supported for downloading network resources:
// Using the builder patternvar fileTransferResult = await httpRemoteService.SendAsync(HttpRequestBuilder.DownloadFile("https://download.visualstudio.microsoft.com/download/pr/a17b907f-8457-45a8-90db-53f2665ee49e/49bccd33593ebceb2847674fe5fd768e/aspnetcore-runtime-8.0.10-win-x64.exe" , @"C:\Workspaces\" , fileExistsBehavior: FileExistsBehavior.Overwrite));// For more detailed usage, see Section 2.1