2.4Downloading Network Resources

Created on Aug 17, 2026~11 min read

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:

cs
// 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.exe

After the file download completes, the framework returns a FileTransferResult object with the following properties:

  • IsSuccess: Whether the transfer completed successfully (bool type). Note: Skipping because the file already exists is also considered a success.
  • RequestUri: The file transfer address (string type). For downloads, this is the download address; for uploads, this is the upload address.
  • FilePath: The file's path (string type).
  • FileSize: The file's size (a long type in bytes).
  • ElapsedMilliseconds: The transfer duration (a long type in milliseconds).
  • StatusCode: The response status (HttpStatusCode type).

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:

cs
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 exists

The 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:

cs
 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()):

bash
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:

cs
 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:

bash
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:

bash
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.00

The type of the progress parameter is FileTransferProgress, which contains the following properties and methods:

  • Properties:

    • FilePath: The file's path (string type).
    • FileName: The file's name (string type).
    • FileSize: The file's size (a long type in bytes).
    • Transferred: The amount of data transferred (a long type in bytes).
    • PercentageComplete: The percentage of the transfer completed (double type).
    • TransferRate: The current transfer rate (a double type in bytes/second).
    • TimeElapsed: The duration from the start of the transfer to the present (TimeSpan type).
    • EstimatedTimeRemaining: The estimated remaining transfer time (TimeSpan type).
  • 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:

cs
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:

bash
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:

bash
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:

cs
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 time

In addition to the approaches above, the following methods are also supported for downloading network resources:

cs
// 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