如何使用C#HttpClient PostAsync显示上传进度

我正在使用Xamarin PCL为Android和iOS创建文件上传应用程序,我已设法实现文件上传和某种进度条,但它无法正常工作。

我在堆栈溢出时看到了一些显示下载进度的答案,但我想通知我的用户有关上传进度的信息并且没有找到任何解决方案。

这是我的代码:

public static async Task PostFileAsync (Stream filestream, string filename, int filesize) { var progress = new System.Net.Http.Handlers.ProgressMessageHandler (); //Progress tracking progress.HttpSendProgress += (object sender, System.Net.Http.Handlers.HttpProgressEventArgs e) => { int progressPercentage = (int)(e.BytesTransferred*100/filesize); //Raise an event that is used to update the UI UploadProgressMade(sender, new System.Net.Http.Handlers.HttpProgressEventArgs(progressPercentage, null, e.BytesTransferred, null)); }; using (var client = HttpClientFactory.Create(progress)) { using (var content = new MultipartFormDataContent ("------" + DateTime.Now.Ticks.ToString ("x"))) { content.Add (new StreamContent (filestream), "Filedata", filename); using (var message = await client.PostAsync ("http://MyUrl.example", content)) { var result = await message.Content.ReadAsStringAsync (); System.Diagnostics.Debug.WriteLine ("Upload done"); return result; } } } } 

显示某种进度,但当进度达到100%时,文件尚未上载。 在收到最后一条进度消息后的某个时间也会打印消息“上传已完成”。

也许进展是显示从设备发出的字节而不是已经上传的字节,所以当它说是100%时,所有字节都只是发出但服务器尚未收到?

编辑:试过这个解决方案: https //forums.xamarin.com/discussion/56716/plans-to-add-webclient-to-pcl,它的工作情况要好一些。

尝试这样的事情:

我遇到了同样的问题。 我通过实现自定义HttpContent修复它。 我使用此对象来跟踪上传进度的百分比,您可以添加事件并收听它。 您应该自定义SerializeToStreamAsync方法。

 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 (eg a FileStream), otherwise the stream can't be copied a second time to a target // stream (eg a NetworkStream). if(content.CanSeek) { content.Position = 0; } else { throw new InvalidOperationException("SR.net_http_content_stream_already_read"); } } contentConsumed = true; } } 

参考:

这是因为你做的数学错了。

更改: int progressPercentage = (int)(e.BytesTransferred*100/filesize);

To: int progressPercentage = (int)(e.BytesTransferred/filesize) *100;

请改用此代码:

  double bytesOut = double.Parse(e.BytesTransferred.ToString()); double totalBytes = double.Parse(filesize.ToString()); double percentage = bytesOut / totalBytes * 100; 

或者你可以简单地使用e.ProgressPercentage