2015-02-26 21 views
5

Wir versuchen, benutzerdefiniert (auf einem Einstellungsbildschirm) optionale gzip-Komprimierung in unserem Client, der HttpClient verwendet, zu implementieren, so dass wir Leistung über mehrere verschiedene Aufrufe protokollieren und vergleichen können Zeitspanne. Unser erster Versuch war einfach bedingt die Header hinzufügen, wie folgt:HttpClient: Bedingte AcceptEncoding-Komprimierung zur Laufzeit

HttpRequestMessage request = new HttpRequestMessage(Method, Uri); 
if (AcceptGzipEncoding) 
{ 
    _client.DefaultRequestHeaders.AcceptEncoding.Add(new System.Net.Http.Headers.StringWithQualityHeaderValue("gzip")); 
} 

//Send to the server 
result = await _client.SendAsync(request); 

//Read the content of the result response from the server 
content = await result.Content.ReadAsStringAsync(); 

dies die richtige Anfrage erstellt, aber die gzip-Antwort wurde nicht auf Rückkehr dekomprimiert, in einer verstümmelten Reaktion zur Folge hat. Ich fand, dass wir die HttpClientHandler beim Bau der HttpClient enthalten hatte:

HttpClient _client = new HttpClient(new HttpClientHandler 
    { 
     AutomaticDecompression = DecompressionMethods.GZip 
    }); 

Das alles gut funktioniert, aber wir möchten ändern, ob der Client die Accept-Encoding: gzip Header zur Laufzeit sendet, und es tut nicht scheint eine beliebige Möglichkeit zu sein, auf die HttpClientHandler zuzugreifen oder sie zu ändern, nachdem sie an den HttpClient-Konstruktor übergeben wurde. Darüber hinaus hat das Ändern der Header des Objekts HttpRequestMessage keine Auswirkungen auf die Header der Anforderung, wenn sie von HttpClientHandler definiert sind.

Gibt es eine Möglichkeit, dies zu tun, ohne die HttpClient bei jeder Änderung neu zu erstellen?

Edit: Ich habe auch versucht, einen Verweis auf die HttpClientHandler ändert AutomaticDecompression zur Laufzeit zu ändern, aber das wirft diese Ausnahme:

Diese Instanz bereits eine oder mehr Anforderungen begonnen hat. Eigenschaften können nur vor dem Senden der ersten Anfrage geändert werden.

+0

neugierig Gerade jetzt, dass Sie gesehen haben, wie praktisch automatische Dekompression ist, warum * nicht * erstellen Sie den Client bei jedem Zeit, dass sich die Einstellung ändert? Genau das würde ich hier machen, außer es gibt einen sehr guten Grund, es nicht zu tun. –

+0

@ ToddMenier Das ist eine sehr gültige Frage. Es ist etwas, das wir in Betracht ziehen, aber es wird ein bisschen Umstrukturierung erfordern, denke ich, weil der gleiche HttpClient in eine Reihe von Bereichen eingebunden ist. Es handelt sich um eine Anwendung mittlerer Größe, die von früheren Entwicklern übernommen wurde. Daher müssen wir Änderungen nur sorgfältig verwalten. Wir werden uns diese Woche anschauen.Danke für die Kommentare und Hilfe. – pcdev

Antwort

1

sich nach den obigen Ausführungen, die Httpclient neu zu erstellen ist wirklich der einzige (robuste) Weg, dies zu tun. Eine manuelle Dekomprimierung kann erreicht werden, aber es scheint sehr schwierig zu sein, zuverlässig/effizient zu bestimmen, ob der Inhalt codiert wurde oder nicht, um zu bestimmen, ob eine Dekodierung angewendet werden soll.

7

Sie sind fast mit dem ersten Beispiel, Sie müssen nur den Strom selbst deflationieren. MS ist GZipSteam wird dabei helfen:

HttpRequestMessage request = new HttpRequestMessage(Method, Uri); 
if (AcceptGzipEncoding) 
{ 
    _client.DefaultRequestHeaders.AcceptEncoding.Add(new System.Net.Http.Headers.StringWithQualityHeaderValue("gzip")); 
} 

//Send to the server 
result = await _client.SendAsync(request); 

//Read the content of the result response from the server 
using (Stream stream = await result.Content.ReadAsStreamAsync()) 
using (Stream decompressed = new GZipStream(stream, CompressionMode.Decompress)) 
using (StreamReader reader = new StreamReader(decompressed)) 
{ 
    content = reader.ReadToEnd(); 
} 
+1

Hmm, es stellt sich heraus, dass diese Antwort funktioniert, es sei denn, der Server entscheidet, die Antwort nicht gzip (oder ist nicht konfiguriert) gzip, dann fällt es um. Leider gibt es keine einfache Möglichkeit, den Header "Content-Encoding" vom HttpResponseMessage-Objekt [siehe diesen Beitrag] zu erhalten (https://social.msdn.microsoft.com/Forums/windowsapps/en-US/cb7417b5-ca3e-44f6) -a272-9e2f8fc5d9b8/portable-httpclient-hides-contentlength-und-contentencoding-headers-with-gzip-encoding? forum = wpdevelop), es sieht also so aus, als ob der HttpClient wirklich neu erstellt werden könnte. Nochmals vielen Dank für Ihre Eingabe. – pcdev

2

Wenn Sie denselben HttpClient verwenden und nur die Komprimierung für einige Anforderungen aktivieren möchten, können Sie die automatische Dekomprimierung nicht verwenden. Wenn die automatische Dekomprimierung aktiviert ist, setzt das Framework auch den Header der Antwort zurück. Das bedeutet, dass Sie nicht herausfinden können, ob die Antwort wirklich komprimiert wurde oder nicht. Übrigens entspricht auch der Header Content-Length der Antwort der Größe des dekomprimierten Inhalts, wenn Sie die automatische Dekomprimierung aktivieren.

Sie müssen also den Inhalt manuell dekomprimieren. Das folgende Beispiel zeigt eine Implementierung für gzip-komprimierten Inhalte (wie auch in @ gezeigt ToddMenier des response):

private async Task<string> ReadContentAsString(HttpResponseMessage response) 
{ 
    // Check whether response is compressed 
    if (response.Content.Headers.ContentEncoding.Any(x => x == "gzip")) 
    { 
     // Decompress manually 
     using (var s = await response.Content.ReadAsStreamAsync()) 
     { 
      using (var decompressed = new GZipStream(s, CompressionMode.Decompress)) 
      { 
       using (var rdr As New IO.StreamReader(decompressed)) 
       { 
        return await rdr.ReadToEndAsync(); 
       } 
      } 
     } 
    else 
     // Use standard implementation if not compressed 
     return await response.Content.ReadAsStringAsync(); 
}