public Task <DownloadData> QueueDownload(UriString url, UriString md5Url, NPath targetDirectory) { var destinationFile = targetDirectory.Combine(url.Filename); var destinationMd5 = targetDirectory.Combine(md5Url.Filename); var result = new DownloadData(url, destinationFile); Action <ITask <NPath>, NPath, bool, Exception> verifyDownload = (t, res, success, ex) => { var count = Interlocked.Increment(ref finishedTaskCount); isSuccessful &= success; if (!success) { exception = ex; } if (count == queuedTasks.Count) { if (!isSuccessful) { DownloadFailed(result, exception); } else { if (!Utils.VerifyFileIntegrity(destinationFile, destinationMd5)) { destinationMd5.Delete(); destinationFile.Delete(); DownloadFailed(result, new DownloadException($"Verification of {url} failed")); } else { DownloadComplete(result); } } } }; var md5Exists = destinationMd5.FileExists(); var fileExists = destinationFile.FileExists(); if (!md5Exists) { destinationMd5.DeleteIfExists(); var md5Download = new DownloadTask(cancellationToken, fs, md5Url, targetDirectory) .Catch(e => DownloadFailed(result, e)); md5Download.OnEnd += verifyDownload; queuedTasks.Add(md5Download); } if (!fileExists) { var fileDownload = new DownloadTask(cancellationToken, fs, url, targetDirectory) .Catch(e => DownloadFailed(result, e)); fileDownload.OnStart += _ => DownloadStart?.Invoke(result); fileDownload.OnEnd += verifyDownload; queuedTasks.Add(fileDownload); } if (fileExists && md5Exists) { var verification = new FuncTask <NPath>(cancellationToken, () => destinationFile); verification.OnEnd += verifyDownload; queuedTasks.Add(verification); } return(aggregateDownloads.Task); }