2013-05-21 9 views
10

Ich muss umfangreiche Daten in einer HTTP-Post-Anfrage an einen Server senden, der Gziped codierte Anfragen unterstützt.So komprimieren HTTP-Anfrage im laufenden Betrieb und ohne Laden von komprimiertem Puffer im Speicher

Ausgehend von einer einfachen

public async Task<string> DoPost(HttpContent content) 
{ 
    HttpClient client = new HttpClient(); 
    HttpResponseMessage response = await client.PostAsync("http://myUri", content); 

    response.EnsureSuccessStatusCode(); 
    return await response.Content.ReadAsStringAsync(); 
} 

Ich habe soeben einen Pre Kompression

public async Task<string> DoPost(HttpContent content, bool compress) 
{ 
    if (compress) 
    content= await CompressAsync(content); 

    return await DoPost(content); 
} 

private static async Task<StreamContent> CompressAsync(HttpContent content) 
{ 
    MemoryStream ms = new MemoryStream(); 
    using (GZipStream gzipStream = new GZipStream(ms, CompressionMode.Compress, true)) 
    { 
    await content.CopyToAsync(gzipStream); 
    await gzipStream.FlushAsync(); 
    } 

    ms.Position = 0; 
    StreamContent compressedStreamContent = new StreamContent(ms); 
    compressedStreamContent.Headers.ContentType = content.Headers.ContentType; 
    compressedStreamContent.Headers.Add("Content-Encoding", "gzip"); 

    return compressedStreamContent; 
} 

Es funktioniert perfekt, aber komprimieren Daten werden komplett in den Speicher geladen, bevor Anfrage senden. I möchte in der Lage sein, Daten während des Sendens in einem Streaming-Weg zu komprimieren.

, es zu tun, ich habe folgenden Code versucht:

private static async Task<HttpContent> CompressAsync2(HttpContent content) 
{ 
    PushStreamContent pushStreamContent = new PushStreamContent(async (stream, content2, transport) => 
    { 
    using (GZipStream gzipStream = new GZipStream(stream, CompressionMode.Compress, true)) 
    { 
     try 
     { 
     await content.CopyToAsync(gzipStream); 
     await gzipStream.FlushAsync(); 
     } 
     catch (Exception exception) 
     { 
     throw; 
     } 
    } 
    }); 
    pushStreamContent.Headers.ContentType = content.Headers.ContentType; 
    pushStreamContent.Headers.Add("Content-Encoding", "gzip"); 

    return pushStreamContent; 
} 

aber es geht nie aus copyToAsync (GZipStream). FlushAsync wird niemals ausgeführt und es wird keine Ausnahme ausgelöst, und Fiddler sieht keinen Post gestartet.

Meine Fragen sind:

  • Warum CompressAsync2 nicht funktioniert?
  • Wie komprimiert man während des Sendens und ohne den komprimierten Puffer im Speicher zu laden?

Jede Hilfe würde sehr geschätzt werden.

+1

'PushStreamContent' unterstützt (derzeit)' async' lambdas nicht. –

+0

@Stephen Cleary: Du hast recht, ich hätte nachsehen sollen! Und ich kann nicht von PushStreamContent abgeleitet werden, um SerializeToStreamAsync zu überlasten (nur zu viele interne). Kannst du eine Lösung sehen? – MuiBienCarlota

+0

Humm, es kann am einfachsten sein, einfach ['PushStreamContent' zu nehmen und es zu modifizieren] (https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Net.Http.Formatting/PushStreamContent.cs), um' 'zu unterstützen asynchrone Lambdas. Es ist seit ein paar Monaten auf meiner "Todo" -Liste, bin einfach nicht dazu gekommen. –

Antwort

12

Versuchen Sie, die CompressedContent Klasse von WebAPIContrib https://github.com/WebApiContrib/WebAPIContrib/blob/master/src/WebApiContrib/Content/CompressedContent.cs

public async Task<string> DoPost(HttpContent content) 
{ 
    HttpClient client = new HttpClient(); 
    HttpResponseMessage response = await client.PostAsync("http://myUri", new CompressedContent(content,"gzip")); 

    response.EnsureSuccessStatusCode(); 
    return await response.Content.ReadAsStringAsync(); 
} 

P. S. mit dass dies nur den Inhalt von .net 4.5 streamen wird. Die .net 4-Version von HttpWebRequest puffert immer gesendete Inhalte.

P.P.S. Das Erstellen eines neuen HttpClient für jede Anfrage ist nicht der beste Weg, um HttpClient zu verwenden. Dadurch wird eine neue TCP-Verbindung für jede Anforderung erstellt.

+0

Wirklich interessante Verbindung: Vielen Dank. Ich muss auf .Net 4.0 (XP benötigt) bleiben. Glaubst du, ich kann gestreamt werden, wenn .Net 4.5 installiert ist, selbst wenn ich für .Net 4.0 kompiliere? – MuiBienCarlota

+0

Ich habe einen lokalen HttpClient nur zur Frage der Einfachheit erstellt. – MuiBienCarlota

+0

@MuiBienCarlota Ich bin mir nicht sicher. Meine Vermutung wäre ja, aber Sie müssen testen. In Bezug auf den HttpClient ... cool, ich sehe es nur sehr viel und ich bin auf einer Mission, es auszustempeln ;-) –

Verwandte Themen