Hello HF,
I was trying to get the most out of the new .Net HttpClient and I decided to make a download manager that allow you to download multiple files asynchronously and control the number of simultaneous downloads.
There are plenty of tutorials on the HttpClient so I had no problem working with it, however, the tricky part was managing the simultaneous downloads. At first, I used Parallel.ForEach which worked fine and then I found this topic on Code Review.
Sorry^^
The answer which was given there was exactly what I was looking for but I didn't quite understand the use of ISourceBlock.
I made few changes to that code and I came up with following:
Well the code works fine but to be honest, I'm just not comfortable with the way ISourceBlock is used here, I think there is a better way of doing it but I can't figure it out since I couldn't find any resources on the web so I need your help to understand this part.
There is a lot more work to do like handling different exceptions, the ability to cancel, pause/resume a download so if you have any thoughts on this please share with us.
I was trying to get the most out of the new .Net HttpClient and I decided to make a download manager that allow you to download multiple files asynchronously and control the number of simultaneous downloads.
There are plenty of tutorials on the HttpClient so I had no problem working with it, however, the tricky part was managing the simultaneous downloads. At first, I used Parallel.ForEach which worked fine and then I found this topic on Code Review.
Code
codereview[.]stackexchange[.]com/questions/18519/real-world-async-and-await-code-exampleThe answer which was given there was exactly what I was looking for but I didn't quite understand the use of ISourceBlock.
I made few changes to that code and I came up with following:
PHP Code
<?php
class DManager
{
public CookieContainer Cookies { get; set; }
public int MaxConnections { get; set; }
public string BaseDirectory { get; set; }
public ISourceBlock<DownloadedFile> DownloadFiles(List<string> links)
{
var Block = new TransformManyBlock<string, DownloadedFile>(
async url =>
{
HttpClientHandler myHandler = new HttpClientHandler()
{
CookieContainer = Cookies
};
return await DownloadFile(url, myHandler);
}, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = MaxConnections });
foreach (string link in links)
Block.Post(link);
Block.Complete();
return Block;
}
private async Task<DownloadedFile[]> DownloadFile(string url, HttpClientHandler handler)
{
DownloadedFile myFile = new DownloadedFile()
{
FileName = Path.Combine(BaseDirectory, Path.GetFileName(url))
};
try
{
using (HttpClient myClient = new HttpClient(handler))
{
myClient.DefaultRequestHeaders.Referrer = new Uri("YOUR LINK");
myClient.DefaultRequestHeaders.UserAgent.TryParseAdd("Mozilla/5.0 (Windows NT 6.1)");
using (HttpResponseMessage Response = await myClient.GetAsync(url))
using (Stream httpStream = await Response.Content.ReadAsStreamAsync())
using (FileStream filestream = new FileStream(myFile.FileName, FileMode.Create, FileAccess.Write, FileShare.None, 4096, true))
await httpStream.CopyToAsync(filestream, 4096);
}
}
catch (Exception ex)
{
Console.WriteLine("Error Downloading: {0}\r\nMessage: {1}", url, ex.Message);
return new DownloadedFile[0];
}
return new[] { myFile };
}
}
internal class DownloadedFile
{
public string FileName { get; set; }
}
Well the code works fine but to be honest, I'm just not comfortable with the way ISourceBlock is used here, I think there is a better way of doing it but I can't figure it out since I couldn't find any resources on the web so I need your help to understand this part.
There is a lot more work to do like handling different exceptions, the ability to cancel, pause/resume a download so if you have any thoughts on this please share with us.


