【问题标题】:How to implement progress reporting for Portable HttpClient如何实现 Portable HttpClient 的进度报告
【发布时间】:2014-01-16 18:09:15
【问题描述】:

我正在编写一个库,打算在桌面(.Net 4.0 及更高版本)、手机(WP 7.5 及更高版本)和 Windows 应用商店(Windows 8 及更高版本)应用程序中使用它。

该库可以使用 Portable HttpClient 库从 Internet 下载文件,并报告下载进度。

我在这里和互联网的其他地方搜索有关如何实施进度报告的文档和代码示例/指南,但这个搜索让我一无所获。

有没有人有文章、文档、指南、代码示例或任何东西可以帮助我实现这一目标?

【问题讨论】:

    标签: c# portable-class-library dotnet-httpclient


    【解决方案1】:

    我编写了以下代码来实现进度报告。代码支持我想要的所有平台;但是,您需要引用以下 NuGet 包:

    • Microsoft.Net.Http
    • Microsoft.Bcl.Async

    代码如下:

    public async Task DownloadFileAsync(string url, IProgress<double> progress, CancellationToken token)
    {
        var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
    
        if (!response.IsSuccessStatusCode)
        {
            throw new Exception(string.Format("The request returned with HTTP status code {0}", response.StatusCode));
        }
    
        var total = response.Content.Headers.ContentLength.HasValue ? response.Content.Headers.ContentLength.Value : -1L;
        var canReportProgress = total != -1 && progress != null;
    
        using (var stream = await response.Content.ReadAsStreamAsync())
        {
            var totalRead = 0L;
            var buffer = new byte[4096];
            var isMoreToRead = true;
    
            do
            {
                token.ThrowIfCancellationRequested();
    
                var read = await stream.ReadAsync(buffer, 0, buffer.Length, token);
    
                if (read == 0)
                {
                    isMoreToRead = false;
                }
                else
                {
                    var data = new byte[read];
                    buffer.ToList().CopyTo(0, data, 0, read);
    
                    // TODO: put here the code to write the file to disk
    
                    totalRead += read;
    
                    if (canReportProgress)
                    {
                        progress.Report((totalRead * 1d) / (total * 1d) * 100);
                    }
                }
            } while (isMoreToRead);
        }
    }
    

    使用方法很简单:

    var progress = new Microsoft.Progress<double>();
    progress.ProgressChanged += (sender, value) => System.Console.Write("\r%{0:N0}", value);
    
    var cancellationToken = new CancellationTokenSource();
    
    await DownloadFileAsync("http://www.dotpdn.com/files/Paint.NET.3.5.11.Install.zip", progress, cancellationToken.Token);
    

    【讨论】:

    • 我知道这是一种死灵评论,但我想补充一点,我使用这种方法并遇到了时间问题,其中有太多的进度输出,它落后于下载的实际进度,导致文件的下载速度比报告的进度快得多。 (我最终使用秒表只报告每秒左右)
    • 不确定是什么原因造成的。我发现它在我的场景中运行良好;包括使用缓冲区大小 4096 字节。
    • put here the code to write the file to disk 应该是什么意思?我假设您的意思是the data,但是什么数据,以及如何编写呢?我是将其附加到文件中,还是一次全部写入?
    • @ProfK data 是一个字节数组,其中包含已读取的确切字节。是的,您一直将其附加到文件中,直到读取最后一个字节。
    【解决方案2】:

    您可以指定 HttpCompletionOption.ResponseHeadersRead,然后在读取流时获取流并报告进度。见this similar question

    【讨论】:

    • 可能类似,但不是我的问题的答案。但是感谢您的链接,它帮助我找到了答案。
    猜你喜欢
    • 2019-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多