C#:HttpClient,上传多个文件时的文件上传进度为MultipartFormDataContent

我正在使用此代码上传多个文件,并且它运行良好。 它使用modernhttpclient库。

public async Task PostImages (int platform, string url, List imageList) { try { int count = 1; var requestContent = new MultipartFormDataContent (); foreach (var image in imageList) { var imageContent = new ByteArrayContent (image); imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse ("image/jpeg"); requestContent.Add (imageContent, "image" + count, "image.jpg"); count++; } var cookieHandler = new NativeCookieHandler (); var messageHandler = new NativeMessageHandler (false, false, cookieHandler); cookieHandler.SetCookies (cookies); using (var client = new HttpClient (messageHandler)) { client.DefaultRequestHeaders.TryAddWithoutValidation ("User-Agent", GetUserAgent (platform)); using (var r = await client.PostAsync (url, requestContent)) { string result = await r.Content.ReadAsStringAsync (); System.Diagnostics.Debug.WriteLine ("PostAsync: " + result); return result; } } } catch (Exception e) { System.Diagnostics.Debug.WriteLine (e.Message); return null; } } 

现在我需要在上传文件时取得进展。 我在谷歌搜索,发现我需要使用ProgressStreamContent

https://github.com/paulcbetts/ModernHttpClient/issues/80

由于ProgressStreamContent包含一个获取流的构造函数,因此我将MultipartFormDataContent转换为流并在其构造函数中使用它。 但是,它不起作用。 上传失败。 我认为它是因为它是所有文件的流,而不是我的后端所期望的。

 public async Task PostImages (int platform, string url, List imageList) { try { int count = 1; var requestContent = new MultipartFormDataContent (); // here you can specify boundary if you need---^ foreach (var image in imageList) { var imageContent = new ByteArrayContent (image); imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse ("image/jpeg"); requestContent.Add (imageContent, "image" + count, "image.jpg"); count++; } var cookieHandler = new NativeCookieHandler (); var messageHandler = new NativeMessageHandler (false, false, cookieHandler); cookieHandler.SetCookies (RestApiPaths.cookies); var stream = await requestContent.ReadAsStreamAsync (); var client = new HttpClient (messageHandler); client.DefaultRequestHeaders.TryAddWithoutValidation ("User-Agent", RestApiPaths.GetUserAgent (platform)); var request = new HttpRequestMessage (HttpMethod.Post, url); var progressContent = new ProgressStreamContent (stream, 4096); progressContent.Progress = (bytes, totalBytes, totalBytesExpected) => { Console.WriteLine ("Uploading {0}/{1}", totalBytes, totalBytesExpected); }; request.Content = progressContent; var response = await client.SendAsync (request); string result = await response.Content.ReadAsStringAsync (); System.Diagnostics.Debug.WriteLine ("PostAsync: " + result); return result; } catch (Exception e) { System.Diagnostics.Debug.WriteLine (e.Message); return null; } } 

我应该怎么做才能让这个工作? 任何帮助表示赞赏

我有一个工作版的ProgressableStreamContent。 请注意,我在构造函数中添加标题,这是原始ProgressStreamContent中的一个错误,它不添加标题!!

 internal class ProgressableStreamContent : HttpContent { ///  /// Lets keep buffer of 20kb ///  private const int defaultBufferSize = 5*4096; private HttpContent content; private int bufferSize; //private bool contentConsumed; private Action progress; public ProgressableStreamContent(HttpContent content, Action progress) : this(content, defaultBufferSize, progress) { } public ProgressableStreamContent(HttpContent content, int bufferSize, Action progress) { if (content == null) { throw new ArgumentNullException("content"); } if (bufferSize <= 0) { throw new ArgumentOutOfRangeException("bufferSize"); } this.content = content; this.bufferSize = bufferSize; this.progress = progress; foreach (var h in content.Headers) { this.Headers.Add(h.Key,h.Value); } } protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) { return Task.Run(async () => { var buffer = new Byte[this.bufferSize]; long size; TryComputeLength(out size); var uploaded = 0; using (var sinput = await content.ReadAsStreamAsync()) { while (true) { var length = sinput.Read(buffer, 0, buffer.Length); if (length <= 0) break; //downloader.Uploaded = uploaded += length; uploaded += length; progress?.Invoke(uploaded, size); //System.Diagnostics.Debug.WriteLine($"Bytes sent {uploaded} of {size}"); stream.Write(buffer, 0, length); stream.Flush(); } } stream.Flush(); }); } protected override bool TryComputeLength(out long length) { length = content.Headers.ContentLength.GetValueOrDefault(); return true; } protected override void Dispose(bool disposing) { if (disposing) { content.Dispose(); } base.Dispose(disposing); } } 

还要注意,它期望HttpContent,而不是流。

这就是你如何使用它。

  var progressContent = new ProgressableStreamContent ( requestContent, 4096, (sent,total) => { Console.WriteLine ("Uploading {0}/{1}", sent, total); });