使用TAP的WebClient进度报告 [英] WebClient progress reporting using TAP

查看:122
本文介绍了使用TAP的WebClient进度报告的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道是否可以在不使用EAP( 基于事件的异步模式 )的情况下报告WebClient进度. (使用EAP)的旧方法是:

I'm wondering if there is a way to report WebClient progress without using EAP(Event-based Asynchronous Pattern). Old way(using EAP) would be:

var client = new WebClient();
client.DownloadProgressChanged += (s,e) => { //progress reporting }
client.DownloadFileCompleted += (s,e) => { Console.Write("download finished" }
client.DownloadFileAsync(file);

使用async/await,可以这样写:

With async/await this can be written as:

var client = new WebClient();
client.DownloadProgressChanged += (s,e) => { //progress reporting }
await client.DownloadFileTaskAsync(file);
Console.Write("downlaod finished");

但是在第二个示例中,我同时使用了EAP和TAP( 基于任务的异步模式 ). 混合两种异步模式被认为是不好的做法吗?

But in the second example i'm using both EAP and TAP(Task-based Asynchronous Pattern). Isn't mixing two patterns of asynchrony considered as a bad practice?

是否有一种无需使用EAP即可实现相同目标的方法? 我已经阅读过有关 IProgress 界面的信息,但我认为无法使用它来报告WebClient进度.

Is there a way to achieve the same without using EAP? I have read about IProgress interface, but I think there is no way to use it to report WebClient progress.

推荐答案

坏消息是答案为否!

好消息是,任何EAP API都可以转换为TAP API.

The good news is that any EAP API can be converted into a TAP API.

尝试一下:

public static class WebClientExtensios
{
    public static async Task DownloadFileTaskAsync(
        this WebClient webClient, 
        Uri address, 
        string fileName, 
        IProgress<Tuple<long, int, long>> progress)
    {
        // Create the task to be returned
        var tcs = new TaskCompletionSource<object>(address);

        // Setup the callback event handler handlers
        AsyncCompletedEventHandler completedHandler = (cs, ce) =>
        {
            if (ce.UserState == tcs)
            {
                if (ce.Error != null) tcs.TrySetException(ce.Error);
                else if (ce.Cancelled) tcs.TrySetCanceled();
                else tcs.TrySetResult(null);
            }
        };

        DownloadProgressChangedEventHandler progressChangedHandler = (ps, pe) =>
        {
            if (pe.UserState == tcs)
            {
                progress.Report(
                    Tuple.Create(
                        pe.BytesReceived, 
                        pe.ProgressPercentage, 
                        pe.TotalBytesToReceive));
            }
        };

        try
        {
            webClient.DownloadFileCompleted += completedHandler;
            webClient.DownloadProgressChanged += progressChangedHandler;

            webClient.DownloadFileAsync(address, fileName, tcs);

            await tcs.Task;
        }
        finally
        {
            webClient.DownloadFileCompleted -= completedHandler;
            webClient.DownloadProgressChanged -= progressChangedHandler;
        }
    }
}

并像这样使用它:

void Main()
{
    var webClient = new WebClient();

    webClient.DownloadFileTaskAsync(
        new Uri("http://feeds.paulomorgado.net/paulomorgado/blogs/en"),
        @"c:\temp\feed.xml",
        new Progress<Tuple<long, int, long>>(t =>
        {
            Console.WriteLine($@"
        Bytes received: {t.Item1,25:#,###}
   Progress percentage: {t.Item2,25:#,###}
Total bytes to receive: {t.Item3,25:#,###}");
        })).Wait();
}

这篇关于使用TAP的WebClient进度报告的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆