我正在学习任务并行库。我有一些使用WebClient类从Web下载数据的旧代码。我想将之前使用Event-based Asynchronous Pattern(EAP)的代码转换为Task-based Asynchronous Pattern (TAP)
我的旧代码如下:
WebClient client1 = new WebClient();
client1.DownloadDataCompleted += (o, e)=>
{
if (e.Cancelled)
{
//code that update UI report download has been canceled.
}
else
{
byte[] s = e.Result;
//code that update UI report downloads has been completed.
}
};
client1.DownloadProgressChanged += ( o, e) =>
{
//code that update UI report downloading progress.
updateProgress(e.ProgressPercentage);
};
//start download asynchronous
client1.DownloadDataAsync(new Uri("http://stackoverflow.com/"));
//code to cancel download.
client1.CancelAsync();
现在使用Task API,我有代码:
WebClient client2 = new WebClient();
Task<byte[]> task = client2.DownloadDataTaskAsync("http://stackoverflow.com/");
task.ContinueWith((antecedent) =>
{
byte[] s = antecedent.Result;
//code that updateUI report download has been completed.
});
//TODO how to code that can cancel the download and report progress?
所以我的问题是:
使用任务方法DownloadDataTaskAsync时,WebClient类是否具有内置api,我可以取消下载并报告下载进度?
答案 0 :(得分:5)
您可以扩展WebClient:
public static class WebClientExtensions
{
public static async Task<byte[]> DownloadDataTaskAsync(this WebClient webClient, string address, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
using (cancellationToken.Register(webClient.CancelAsync))
{
return await webClient.DownloadDataTaskAsync(address);
}
}
}
然后调用扩展方法:
var data = await webClient.DownloadDataTaskAsync("http://stackoverflow.com/", cancellationToken);
答案 1 :(得分:0)
没有支持取消的重载,因此您无法取消该异步操作(您可能需要阅读How do I cancel non-cancelable async operations?)。
但是,您可以在该操作之上添加超时或取消,以使您的代码继续进行。 对于进度报告,您可能需要查看WebClient.DownloadProgressChanged Event。它似乎符合您的需求。
答案 2 :(得分:0)
public static async Task<byte[]> DownloadDataTaskAsync(this WebClient obj, Uri address, CancellationToken cancellationToken)
{
var tcs = new TaskCompletionSource<bool>();
var task = obj.DownloadDataTaskAsync(address);
using (cancellationToken.Register(s => ((TaskCompletionSource<bool>)s).TrySetResult(true), tcs))
{
if (task != await Task.WhenAny(task, tcs.Task))
{
throw new OperationCanceledException(cancellationToken);
}
}
return await task;
}
来自@Dartal的修改版
使用任务完成源解决问题,或者您可以参考How do I cancel non-cancelable async operations?
然后,您可以使用CancelAsync强制关闭连接