6.21Downloading Network Resources

Created on Aug 17, 2026~13 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, compressed packages, installation software, and so on. There are multiple ways to download network resources. The most common is to send an HTTP request, receive the returned Stream, and then write it to the local disk and save it as the corresponding file.

Downloading in the Conventional Way by Receiving the Stream

cs
// Get the response Streamvar stream = await httpRemoteService.GetAsStreamAsync("https://furion.net/img/furionlogo.png");// Create a file stream and write to itusing var fileStream = new FileStream(@"C:\Workspaces\furionlogo.png", FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true);await contentStream.CopyToAsync(fileStream);

However, this way of downloading network resources is not flexible enough when faced with various complex scenarios — for example, it cannot track download progress in real time, properly handle the case where the file already exists, or implement chunked downloads. In addition, it may require developers to write more additional code. Therefore, the framework integrates features specifically designed for downloading network resources to address these issues.

Downloading with the framework's built-in dedicated download functionality

The following example shows how to use the framework's built-in download functionality to download the ASP.NET Core runtime:

cs
// Downloads the ASP.NET Core runtime from the specified URL and saves 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 containing the following properties:

  • IsSuccess: whether the transfer completed successfully (bool type). Note: skipping because the file exists is also considered a success.
  • RequestUri: the file transfer URL (string type).
  • FilePath: the path of the file (string type).
  • FileSize: the size of the file (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 is thrown: System.InvalidOperationException: The destination path 'C:\Workspaces\aspnetcore-runtime-8.0.10-win-x64.exe' already exists.. In this case, you can use the fileExistsBehavior parameter to specify the behavior when the file exists:

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 the file if it 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()); // Outputs 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), 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 the console in real time, it is recommended to use the UpdateConsoleProgressAsync() method. The example is as 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() // Updates 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 progress parameter is of type FileTransferProgress and contains the following properties and methods:

  • Properties:

    • FilePath: the path of the file (string type).
    • FileName: the name of the file (string type).
    • FileSize: the size of the file (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 per second).
    • TimeElapsed: the duration from the start of the transfer to now (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 achieve 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 in real time on the same screen 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\";// Downloads 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 at the same time, and each file's progress bar refreshes 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