2017-03-03 34 views
11

我正在製作一個將文件上傳到Facebook的UWP應用程序,我使用自定義的HttpContent以4k塊的形式上傳文件,以儘量減少大文件(> 100mb)的內存使用量並報告進度。HttpClient在上傳前讀取整個文件。 UWP

我定製HttpContent UploadWithProgressHttpContent:

class UploadWithProgressHttpContent : HttpContent 
{ 
    private readonly IProgress<OperationProgress> _progress; 
    private readonly OperationProgress _data; 
    private readonly Stream _file; 
    private readonly int _bufferSize; 
    private readonly CancellationToken _token; 

    public UploadWithProgressHttpContent(
     IProgress<OperationProgress> progress, 
    OperationProgress data, 
    Stream file, 
    int bufferSize, 
    CancellationToken token) 
{ 
    _progress = progress; 
    _data = data; 
    _file = file; 
    _bufferSize = bufferSize; 
    _token = token; 
} 



protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) 
{ 
    return CopyStreamWithProgress(_file, stream, _progress, _token, _data, _bufferSize); 
} 

public static async Task<Stream> CopyStreamWithProgress(
    Stream source, 
    Stream destination, 
    IProgress<OperationProgress> progress, 
    CancellationToken token, 
    OperationProgress progressData, 
    int bufferSize 
    ) 
{ 
    int read, offset = 0; 
    var buffer = new byte[bufferSize]; 
    using (source) 
    { 
     do 
     { 
      read = await source.ReadAsync(buffer, 0, bufferSize, token); 

      await destination.WriteAsync(buffer, 0, read, token); 

      offset += read; 
      progressData.CurrentSize = offset; 
      progress.Report(progressData); 
     } while (read != 0); 
    } 

    return destination; 
} 
} 

什麼我遇到(使用招)是整個文件被存儲在上傳開始前(我的進度條達到100%上傳甚至開始前的推杆)。

我曾嘗試將TransferEncodingChunked設置爲true,並設置文件內容的長度,但問題依然存在。

上傳來源在PCL中(如果有的話)。我正在使用最新版本的System.Net.Http。如果需要,我使用的方式與MediaFire SDK

完全相同,謝謝你的幫助。

編輯:添加HttpClient的用法:

public async Task<T> Upload<T>(Stream fileStream, string fileName) 
{ 
    var handler = new HttpClientHandler(); 


    var cli = new HttpClient(handler); 

    foreach (var header in Headers) 
    { 
     cli.DefaultRequestHeaders.Add(header.Key, header.Value); 
    } 

    var parameters = new MultipartFormDataContent(); 
    foreach (var parameter in Parameters) 
    { 
     parameters.Add(new StringContent(parameter.Value), parameter.Key); 
    } 

    if (fileStream != null) 
    { 
     var fileContent = new UploadWithProgressHttpContent(ProgressOperation, ProgressData, fileStream, 
      _chunkBufferSize, Token, fileStream.Length); 

     fileContent.Headers.ContentType = new MediaTypeHeaderValue(MimeTypeHelper.GetMimeType(fileName)); 
     fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue(StreamParamName); 
     fileContent.Headers.ContentDisposition.FileName = fileName; 
     fileContent.Headers.ContentLength = fileStream.Length; 
     parameters.Add(fileContent, StreamParamName); 
    } 

    var req = new HttpRequestMessage(method, Path) { Content = parameters }; 
    if (fileStream != null) 
     req.Headers.TransferEncodingChunked = true; 


    var completionOption = HttpCompletionOption.ResponseContentRead; 


    var resp = await cli.SendAsync(req, completionOption, Token).ConfigureAwait(false); 

    return await DeserializeObject<T>(resp); 
} 
+0

我無法修復使用自定義HttpContent這個問題,我的替代是使用StreamContent,並作出流裝飾器報道讀取進展。通過使用StreamContent,HttpClient可以在不將內容全部帶入內存的情況下對內容進行流式傳輸。 – DVD

+0

不完全是,我使用的是自定義的httpcontent,我已經檢查過使用流的內容,它的工作方式和預期的一樣,我只是想知道爲什麼它不能與自定義的httpcontent一起工作,或者如果有任何方式的話。 – DVD

+0

你能分享一下HttpClient的代碼嗎?順便說一句。我會考慮使用Wire Shark來代替(不確定是否將httpd代理添加爲fiddler並不會影響流量)。 –

回答

0

在這個問題上浪費了大量時間後,它認爲這是一個HttpClient實現問題。 因此,如果您想將內容流式傳輸到服務器(並報告進度),最好的方法是使用StreamContent並裝飾讀取以報告進度。

注意:這是真實的版本4.3.1的System.Net.Http和版本2.2.29 Microsoft.Net.Http金塊包