HttpClient上传进度条

8
我希望在WPF中运行具有进度条的异步上传(最好使用PCL以便在Xamarin和SL中重用代码)。
我一直在尝试使用System.Net.HttpClient。不幸的是,PutAsync没有提供任何进度通知。(我知道Windows.Web.Http.HttpClient可以做到这一点,但它在WPF中不可用,也不在PCL中。)
对于下载,实现自己的进度条相当容易,如此处所述。您只需传递ResponseHeadersRead选项,使流在返回标头后立即可用,然后按块读取它,随着读取的进行逐步增加进度条。但是对于上传,这种技术不起作用-您需要一次性将所有上传数据传递给PutAsync,因此没有机会递增计数器。
我还想知道是否可以使用HttpClient.SendAsync。我希望能够像处理异步HttpWebRequest一样处理它(在其中,您可以在写入HttpWebRequest.GetRequestStream时递增计数器,如此处所述)。但不幸的是,HttpClient.SendAsync没有给您可写的流,因此这不起作用。
那么HttpClient是否支持具有非阻塞UI和进度条的上传呢?这似乎是一个适度的需求。还是我应该使用另一个类?非常感谢您。
2个回答

6
假设HttpClient(和底层网络堆栈)没有缓冲,您可以通过覆盖HttpContent.SerializeToStreamAsync来完成以下操作:
        const int chunkSize = 4096;
        readonly byte[] bytes;
        readonly Action<double> progress;

        protected override async Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext context)
        {
            for (int i = 0; i < this.bytes.Length; i += chunkSize)
            {
                await stream.WriteAsync(this.bytes, i, Math.Min(chunkSize, this.bytes.Length - i));
                this.progress(100.0 * i / this.bytes.Length);
            }
        }

为了避免被HttpClient缓冲,你需要提供内容长度(例如:实现HttpContent.TryComputeLength或设置头文件),或启用HttpRequestHeaders.TransferEncodingChunked。这是必要的,因为否则HttpClient无法确定内容长度标头,所以它首先将整个内容读入内存中。
在电话8上,您还需要禁用AllowAutoRedirect,因为WP8在处理重定向后发布的方式上存在错误(解决方法是首先发出HEAD,获取重定向的URL,然后使用AllowAutoRedirect = false将帖子发送到最终URL)。

是的,那似乎可以工作。(到目前为止,我只在WPF、.net 4.5.1中进行了测试。)非常感谢! - thund

0

上传文件并显示进度的简单方法

我有同样的需求,经过一些尝试后发现,你可以通过跟踪要上传的文件的 FileStream 的 Position 来轻松获取字节精确的上传进度。

以下是一种实现方式...

FileStream fileToUpload = File.OpenRead(@"C:\test.mp3");

HttpContent content = new StreamContent(fileToUpload);
HttpRequestMessage msg = new HttpRequestMessage{
    Content=content,
    RequestUri = new Uri(--yourUploadURL--)
}

bool keepTracking = true; //to keep tracking thread running
new Task(new Action(() => { progressTracker(fileToUpload, ref keepTracking); })).Start();
var result = httpClient.SendAsync(msg).Result;
keepTracking = false; //to stop the tracking thread

函数progressTracker()的定义如下:

void progressTracker(FileStream streamToTrack, ref bool keepTracking)
{
    int prevPos = -1;
    while (keepTracking)
    {
        int pos = (int)Math.Round(100 * (streamToTrack.Position / (double)streamToTrack.Length));
        if (pos != prevPos)
        {
            Console.WriteLine(pos + "%");

        }
        prevPos = pos;

        Thread.Sleep(100); //only update progress every 100ms
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接