Here is a
DownloadService
with a batching mode (10 at a time) for grabbing files, like images.
public class DownloadService
{
public string SavePath { get; set; }
private IHttpClientFactory _httpFactory { get; }
public DownloadService(IHttpClientFactory httpFactory)
=> _httpFactory = httpFactory;
public async Task<bool> DownloadToFileAsync(string url, string filePath)
{
Console.WriteLine($"Downloading: {url} as {filePath}");
filePath = Path.Combine(SavePath, filePath);
var request = new HttpRequestMessage(HttpMethod.Get, url);
var client = _httpFactory.CreateClient();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
try
{
await using Stream webStream = await response.Content.ReadAsStreamAsync();
await using FileStream fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write,
FileShare.None,
bufferSize: 64 * 1024, useAsync: true);
await webStream.CopyToAsync(fileStream).ConfigureAwait(false);
}
catch (Exception ex)
{
throw;
}
return true;
}
Console.WriteLine($"StatusCode: {response.StatusCode} for {url}");
return false;
}
public async Task<bool> BulkDownloadToFileAsync(Dictionary<string, string> jobs)
{
var batches = jobs.Chunk(10);
foreach (var batch in batches)
{
bool success = (await Task.WhenAll(batch.Select(job => DownloadToFileAsync(job.Value, job.Key)))
.ConfigureAwait(false))
.All(x => x);
if (!success)
Debugger.Break();
await Task.Delay(200).ConfigureAwait(false);
}
return true;
}
}
To use:
var builder = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddHttpClient();
services.AddTransient<DownloadService>();
}).UseConsoleLifetime();
var host = builder.Build();
using var serviceScope = host.Services.CreateScope();
var services = serviceScope.ServiceProvider;
var jobs = new Dictionary<string, string>
{
["local_save_filename"] = "remote_url_to_file",
["local_save_filename"] = "remote_url_to_file",
["local_save_filename"] = "remote_url_to_file",
};
var downloadService = services.GetRequiredService<DownloadService>();
downloadService.SavePath = @"path_to_save_downloads";
var success = await downloadService
.BulkDownloadToFileAsync(jobs)
.ConfigureAwait(false);
Notes:
* Best practice is to use the
HttpClientFactory
when working with the
HttpClient
- ref:
HttpClient guidelines for .NET - .NET | Microsoft Learn[
^]
* The above code is for demonstration purposes only and is not production ready.
I am sure that you get the idea and can adapt to your needs.
Hope this helps!