2017-03-03 4 views
11

Ich mache eine UWP-App, die Dateien nach Facebook hochlädt, ich benutze einen benutzerdefinierten HttpContent, um die Dateien in 4k-Blöcken hochzuladen, um die Speichernutzung für große Dateien (> 100mb) zu minimieren und den Fortschritt zu melden.HttpClient liest die gesamte Datei vor dem Upload. UWP

Meine benutzerdefinierte 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; 
} 
} 

Was ich erlebe (mit Fiedler) ist, dass die gesamte Datei im Speicher vor dem Upload beginnt geputtet wird (meine Fortschrittsanzeige 100% erreicht, bevor der Upload selbst beginnt).

Ich habe versucht, die TransferEncodingChunked zu true, und die Datei Inhalt Länge einstellen, aber das Problem bleibt.

Die Upload-Quelle befindet sich in einem PCL (wenn es darauf ankommt). Ich verwende die neueste Version von System.Net.Http. Bei Bedarf benutze ich das genau so, wie es in der MediaFire SDK

verwendet wird. Danke für jede Hilfe.

EDIT: die Httpclient Nutzung Hinzugefügt:

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

wahr ich nicht dieses Problem mit einem benutzerdefinierten beheben könnte HttpContent wurde meine Alternative einer StreamContent verwendet, und eine zu machen Stream Decorator, der beim Lesen Fortschritte gemeldet hat. Mit einem StreamContent streamt HttpClient den Inhalt, ohne ihn (alle) in den Speicher zu bringen. – DVD

+0

Nicht genau, ich benutze einen benutzerdefinierten httpcontent, ich überprüfe bereits, dass mit einem Stream-Inhalt funktioniert es wie erwartet, ich will nur wissen, warum es nicht mit einem benutzerdefinierten httpcontent funktioniert, oder wenn es irgendeinen Weg es wäre. – DVD

+0

Kannst du auch den Stückcode um HttpClient herum teilen? Übrigens. Ich würde in Betracht ziehen, Drahthai stattdessen zu verwenden (nicht sicher, ob das Hinzufügen von Fiddler als http-Proxy nicht mit dem Verkehr unordentlich ist). –

Antwort

0

Nach Stunden verschwendete dieses Problem, es scheint, dass dies ein HttpClient-Implementierungsproblem ist. Wenn Sie also Inhalte an einen Server streamen (und den Fortschritt melden möchten), verwenden Sie am besten eine StreamContent und dekorieren Sie die Lesevorgänge, um den Fortschritt zu melden.

Hinweis: Dies ist auf die 4.3.1 Version von System.Net.Http und Version 2.2.29 Microsoft.Net.Http Nugget Pakete

Verwandte Themen