使用HttpWebRequest和TPL获取进度更新(任务)

我想跟踪发生在单独线程上的下载进度。我知道System.Net.WebClient有一个DownloadStringAsync方法,但它不直接与新的TP​​L类型(TaskFactory,Task等)一起工作。

  • 可以使用HttpRequest和HttpResponse类跟踪进度吗?
  • 跟踪进度的最佳类别是什么?开销越少越好。
  • 是否有时候响应的大小未知,即进度无法跟踪?
  • 无论何时取得进展,与UI线程进行同步的最佳方式是什么?

大多数示例显示任务只在整个任务完成后更新UI。这些示例使用延续来获取UI同步上下文,从而避免需要直接使用Dispatcher。

这个想法是显示一个网格视图(在WPF中)与所有的进度条下载。我将一直添加新行和更新进度条。我试图避免将这些代码变成一团糟。

0
额外
意见: 1

1 答案

DownloadStringAsync和其他事件方法在.NET 4.0中与TPL很好地协作(检查EAP和TPL)。一般来说,TPL通过TaskCompletionSource支持事件异步编程。通过Task.FromAsync方法支持Begin/EndXXX模型(APM)。您可以找到 TPL和Traditional .NET异步编程的详细说明。

ParallelExtensionExtras 库有一组WebClient扩展像DownloadStringTask这样的方法返回一个任务,当相应的事件被触发时这个任务完成。

以下代码将创建一个完成下载任务后的任务:

    public Task DownloadStringTask(WebClient client,Uri uri)
    {
        var tcs = new TaskCompletionSource();
        client.DownloadStringCompleted += (o, a) => tcs.SetResult(a.Result);
        client.DownloadStringAsync(uri);
        return tcs.Task;
    }

至于更新用户界面,您可以轻松使用DownloadProgressChanged事件来提供反馈,例如:

using (var client = new WebClient())
{
    client.DownloadProgressChanged += (o, a) => Console.WriteLine("{0}",a.ProgressPercentage);

    var task = DownloadStringTask(client,new Uri("http://www.stackoverflow.com"));
    var write=task.ContinueWith(t => Console.WriteLine("Got {0} chars", t.Result.Length));
    write.Wait();
    Console.ReadKey();
}

如果使用数据绑定将进度值提供给进度条,则可以更新进度值属性。如果你直接更新进度条(不是一个好主意),你将不得不使用进度条的调度程序来调用UI线程,例如。喜欢这个

    void UpdateProgress(int percent)
    {
        if (progressBar1.CheckAccess())
            progressBar1.Value = percent;
        else
        {                
            progressBar1.Dispatcher.Invoke(new Action(()=>UpdateProgress(percent)));
        }
    }
    ....
    client.DownloadProgressChanged += (o, a) => UpdateProgress(a.ProgressPercentage);
0
额外