1

I have a Web Api that send me the responses compress with brotli and I have a console app that use a HttpClient by request the data to my WebApi. I need decompress the data send by my WebApi.

For .Net Core 2.2

Startup.cs

//Compresión de respuestas del servidor

services.Configure<BrotliCompressionProviderOptions>(opciones =>
                opciones.Level = CompressionLevel.Optimal
);

services.AddResponseCompression(opciones =>
{
    opciones.EnableForHttps = true;
    opciones.Providers.Add<BrotliCompressionProvider>();
});

ConseleApp

using (var client = new HttpClient(handler)){
    client.BaseAddress = new Uri(BASE_URL);
    client.Timeout = new TimeSpan(0, 0, TIMEOUT_SECONDS);
    HttpRequestHeaders headers = client.DefaultRequestHeaders;
    headers.Add("X-User", Environment.UserName);
    headers.Add("Accept-Encoding", "br"); //gzip
    HttpResponseMessage response = null;

    response = await client.GetAsync($"{requestUrl}");
    if (response.IsSuccessStatusCode)
    {
        string strResult = await response.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<T>(strResult);
    }
}

The strResult is not JSON. . .

Jonhy.Olivas
  • 25
  • 2
  • 6

3 Answers3

5

Assuming you are using the HttpClientFactory that was included in .NET Core 2.1 then you can just create a delegating handler which will intercept and decompress it before handing the full payload to your code.

using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using BrotliSharpLib;

internal sealed class BrotliCompressionHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
        if (!response.Content.Headers.TryGetValues("Content-Encoding", out var ce) || ce.First() != "br")
            return response;
        var buffer = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
        response.Content = new ByteArrayContent(Brotli.DecompressBuffer(buffer, 0, buffer.Length));
        return response;
    }
}

Then just wire up the handler to the client(s) you need to support brotli with.

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddTransient<BrotliCompressionHandler>()
        .AddHttpClient("github", c =>
        {
            c.BaseAddress = new Uri("https://api.github.com/");
            c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
            c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
        })
        .AddHttpMessageHandler<BrotliCompressionHandler>();
}
Buvy
  • 1,174
  • 12
  • 16
3

I've implemented as follow with Brotli.NET:

static async Task<string> GetLinkTitle(string link) => await Task.Run(async () =>
{
    using (var httpGet = new System.Net.Http.HttpClient())
    {
        httpGet.DefaultRequestHeaders.Add("Accept-Encoding", "br");
        var response = await httpGet.GetAsync($"http://www.youtube.com/oembed?url={link}&format=xml");
        
        string responseContent;
        using(var brotli = new Brotli.BrotliStream(await response.Content.ReadAsStreamAsync(), System.IO.Compression.CompressionMode.Decompress, true))
        {
            var streamReader = new StreamReader(brotli);
            responseContent = streamReader.ReadToEnd();
        }

        var doc = XDocument.Parse(responseContent);
        return !response.IsSuccessStatusCode ? $"ERROR: {response.StatusCode} - {link}".Dump() : doc.Descendants("title").FirstOrDefault().Value;
    }
});
  • It appears, Brotli.NET (rather than BrotliSharpLib) relies on CPU dependent libraries, from what I can see it only supports x64/x86. Has anyone had hands-on experience with that? – Thomas Williams Dec 16 '22 at 20:37
1

Did you try one of the .Net libraries such as:

  1. https://www.nuget.org/packages/Brotli.NET/
  2. https://www.nuget.org/packages/BrotliSharpLib/

both support Brotli compression and decompression, without the need for .Net native support. they claim to be faster than the .Net implementation too.

Micha Kaufman
  • 777
  • 7
  • 11