如何取消和进度报告WebClient.DownloadDataTaskAsync方法返回的任务?

时间:2013-12-22 04:44:39

标签: c# .net task-parallel-library

我正在学习任务并行库。我有一些使用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,我可以取消下载并报告下载进度?

3 个答案:

答案 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强制关闭连接

Aborting a WebClient.DownloadFileAsync operation