2016-12-29 721 views
1

我使用此代碼上傳多個文件,效果很好。它使用現代的HTTP客戶端庫。C#:HttpClient,將多文件上傳爲MultipartFormDataContent時的文件上傳進度

public async Task<string> PostImages (int platform, string url, List<byte []> 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<string> PostImages (int platform, string url, List<byte []> 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; 
    } 
} 

我應該在這裏做些什麼來使這個工作?任何幫助表示讚賞

+0

你必須使用MultiPartContent而不是ByteArrayContent –

+0

我把文件當作字節數組。 – HeisenBerg

+0

服務器不接受字節數組,http服務器大多需要多部分表單編碼內容,它是服務器期望數據的方式,而不是你如何發送 –

回答

6

我有一個工作版本的ProgressableStreamContent。請注意,我在構造函數中添加了頭文件,這是原始ProgressStreamContent中的一個錯誤,它不會添加頭文件!

internal class ProgressableStreamContent : HttpContent 
{ 

    /// <summary> 
    /// Lets keep buffer of 20kb 
    /// </summary> 
    private const int defaultBufferSize = 5*4096; 

    private HttpContent content; 
    private int bufferSize; 
    //private bool contentConsumed; 
    private Action<long,long> progress; 

    public ProgressableStreamContent(HttpContent content, Action<long,long> progress) : this(content, defaultBufferSize, progress) { } 

    public ProgressableStreamContent(HttpContent content, int bufferSize, Action<long,long> 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); 
    }); 
+0

它的工作。謝謝.... – HeisenBerg