HttpClient: Conditionally set AcceptEncoding compression at runtime

We are trying to implement a custom (on the settings screen) additional gzip compression in our client that uses HttpClient , so we can register and compare the performance of several different calls over a certain period of time. Our first attempt was to simply conditionally add a header as follows:

 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(); 

This created the correct request, but the gzipped response was not unpacked upon return, which resulted in a distorted response. I found that when building the HttpClient we had to enable the HttpClientHandler :

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

This all works well, but we would like to change whether the client sends the Accept-Encoding: gzip header at run time, and there seems to be no way to access or change the HttpClientHandler after passing it to the HttpClient constructor. In addition, changing the headers of the HttpRequestMessage object does not affect the request headers if they are defined by the HttpClientHandler .

Is there a way to do this without recreating the HttpClient every time this changes?

Edit: I also tried changing the reference to the HttpClientHandler to change AutomaticDecompression at runtime, but this is an exception to this exception:

This instance has already launched one or more queries. Properties can only be changed before sending the first request.

+6
source share
3 answers

According to the comments above, re-creating the HttpClient is really the only (reliable) way to do this. Manual decompression can be achieved, but it seems very difficult to reliably / efficiently determine whether the content has been encoded or not, in order to determine whether to use decoding.

+1
source

You are almost there with the first example, you just need to blow off the flow yourself. MS GZipSteam will help with this:

 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(); } 
+7
source

If you want to use the same HttpClient and only want to enable compression for some requests, you cannot use automatic decompression. When automatic decompression is enabled, the environment also resets the Content-Encoding header of the response. This means that you cannot figure out if the answer was really compressed or not. By the way, the Content-Length header of the response corresponds to the size of the unpacked content if you enable automatic decompression.

So you need to deploy the content manually. The following example shows an implementation for gzip-compressed content (as also shown in @ToddMenier's answer ):

 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(); } 
+2
source

Source: https://habr.com/ru/post/983072/


All Articles