如何计算与HttpClient的PostAsync进展? [英] How can I calculate progress with HttpClient PostAsync?

查看:717
本文介绍了如何计算与HttpClient的PostAsync进展?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的Windows Store应用(C#)我需要上传 MultipartFormDataContent (一些字符串的内容和一些文件),以服务器和响应得到一个巨大的文件。这个问题 - 我不能使用 BackgroundDownloaders 为。我只能用一个请求为

In my Windows Store App (c#) I need to upload MultipartFormDataContent (some strings content and some files) to server and get a huge file at response. The problem - I can't use BackgroundDownloaders for that. I can only use one request for that.

我用 HttpClient.PostAsync 方法:

 using (var client = new HttpClient(httpClientHandler))
            {
                using (var content = new MultipartFormDataContent())
                {
                    content.Add(...); // prepare all strings and files content
                    try
                    {
                        using (var response = await client.PostAsync(url, content))
                        {
                            if (response.StatusCode == HttpStatusCode.OK)
                            {
                                var inputBytes = await response.Content.ReadAsByteArrayAsync();
                                // some operations with inputBytes 
                            }
                            ......
                        }
                    }
                }
            }

我的问题是:我如何计算这个操作的进展如何?

My question is: How can I calculate progress of this operation?

注意: - Windows 8中,我不能使用 Windows.Web.Http.HttpClient <我的目标/ code>(最低支持的客户端Windows 8.1)。只有 System.Net.Http.HttpClient

Note: My target - Windows 8. And I can't use Windows.Web.Http.HttpClient (Minimum supported client Windows 8.1). Only System.Net.Http.HttpClient

推荐答案

我面临同样的问题。我通过实现自定义的固定它 HttpContent 。我使用这个对象来跟踪上传进度百分比,你可以添加一个事件来,听它。你应该定义 SerializeToStreamAsync

I faced same issue. I fixed it by implementing custom HttpContent. I use this object to track percentage of upload progress, you can add an event to and listen it. You should customize SerializeToStreamAsync method.

internal class ProgressableStreamContent : HttpContent
{
    private const int defaultBufferSize = 4096;

    private Stream content;
    private int bufferSize;
    private bool contentConsumed;
    private Download downloader;

    public ProgressableStreamContent(Stream content, Download downloader) : this(content, defaultBufferSize, downloader) {}

    public ProgressableStreamContent(Stream content, int bufferSize, Download downloader)
    {
        if(content == null)
        {
            throw new ArgumentNullException("content");
        }
        if(bufferSize <= 0)
        {
            throw new ArgumentOutOfRangeException("bufferSize");
        }

        this.content = content;
        this.bufferSize = bufferSize;
        this.downloader = downloader;
    }

    protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
    {
        Contract.Assert(stream != null);

        PrepareContent();

        return Task.Run(() =>
        {
            var buffer = new Byte[this.bufferSize];
            var size = content.Length;
            var uploaded = 0;

            downloader.ChangeState(DownloadState.PendingUpload);

            using(content) while(true)
            {
                var length = content.Read(buffer, 0, buffer.Length);
                if(length <= 0) break;

                downloader.Uploaded = uploaded += length;

                stream.Write(buffer, 0, length);

                downloader.ChangeState(DownloadState.Uploading);
            }

            downloader.ChangeState(DownloadState.PendingResponse);
        });
    }

    protected override bool TryComputeLength(out long length)
    {
        length = content.Length;
        return true;
    }

    protected override void Dispose(bool disposing)
    {
        if(disposing)
        {
            content.Dispose();
        }
        base.Dispose(disposing);
    }


    private void PrepareContent()
    {
        if(contentConsumed)
        {
            // If the content needs to be written to a target stream a 2nd time, then the stream must support
            // seeking (e.g. a FileStream), otherwise the stream can't be copied a second time to a target 
            // stream (e.g. a NetworkStream).
            if(content.CanSeek)
            {
                content.Position = 0;
            }
            else
            {
                throw new InvalidOperationException("SR.net_http_content_stream_already_read");
            }
        }

        contentConsumed = true;
    }
}

这篇关于如何计算与HttpClient的PostAsync进展?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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