简体   繁体   English

使用TAP的WebClient进度报告

[英]WebClient progress reporting using TAP

I'm wondering if there is a way to report WebClient progress without using EAP( Event-based Asynchronous Pattern ). 我想知道是否有一种方法可以在不使用EAP( 基于事件的异步模式 )的情况下报告WebClient进度。 Old way(using EAP) would be: (使用EAP)的旧方法是:

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

With async/await this can be written as: 使用async / await可以写成:

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

But in the second example i'm using both EAP and TAP( Task-based Asynchronous Pattern ). 但是在第二个示例中,我同时使用了EAP和TAP( 基于任务的异步模式 )。 Isn't mixing two patterns of asynchrony considered as a bad practice? 混合两种异步模式是否被视为不好的做法?

Is there a way to achieve the same without using EAP? 有没有不使用EAP就能达到相同目的的方法? I have read about IProgress interface, but I think there is no way to use it to report WebClient progress. 我已经阅读了有关IProgress接口的信息,但是我认为无法使用它来报告WebClient进度。

The bad news is that the answer is NO! 坏消息是答案是否定的!

The good news is that any EAP API can be converted into a TAP API. 好消息是,任何EAP API都可以转换为TAP API。

Try this: 尝试这个:

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;
        }
    }
}

And just use it like this: 就像这样使用它:

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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM