2016-12-29 11 views
1

Я использую этот код для загрузки нескольких файлов, и он работает очень хорошо. Он использует библиотеку modernhttpclient.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