How to use HttpClientHandler with HttpClientFactory in .NET Core
Asked Answered
R

2

59

I want to use the HttpClientFactory that is available in .NET Core 2.1 but I also want to use the HttpClientHandler to utilize the AutomaticDecompression property when creating HttpClients.

I am struggling because the .AddHttpMessageHandler<> takes a DelegatingHandler not a HttpClientHandler.

Does anyone know how to get this to work?

Thanks, Jim

Rettke answered 7/6, 2018 at 18:17 Comment(0)
G
25

Actually I'm not using automatic decompression but the way to achieve this is to properly register http client

services.AddHttpClient<MyCustomHttpClient>()
   .ConfigureHttpMessageHandlerBuilder((c) =>
     new HttpClientHandler()
     {
        AutomaticDecompression = System.Net.DecompressionMethods.GZip
     }
   )
   .AddHttpMessageHandler((s) => s.GetService<MyCustomDelegatingHandler>())
Gav answered 8/6, 2018 at 6:19 Comment(3)
Did not work for me . Had to use .ConfigureHttpMessageHandlerBuilder(builder => { builder.PrimaryHandler = new HttpClientHandler() { UseDefaultCredentials = true }; builder.Build(); })Carvelbuilt
More properly use ConfigurePrimaryHttpMessageHandler() methodMiddlemost
The first call to ConfigureHttpMessageHandlerBuilder in your solution does absolutely nothing, that method takes an Action<T> and you're just returning a value which is immediately discarded: learn.microsoft.com/en-us/dotnet/api/…Bike
M
40

More properly to define primary HttpMessageHandler via ConfigurePrimaryHttpMessageHandler() method of HttpClientBuilder. See example below to configure typed client how.

services.AddHttpClient<TypedClient>()
    .ConfigureHttpClient((sp, httpClient) =>
    {
        var options = sp.GetRequiredService<IOptions<SomeOptions>>().Value;
        httpClient.BaseAddress = options.Url;
        httpClient.Timeout = options.RequestTimeout;
    })
    .SetHandlerLifetime(TimeSpan.FromMinutes(5))
    .ConfigurePrimaryHttpMessageHandler(x => new HttpClientHandler() 
    {
        AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
    })
    .AddHttpMessageHandler(sp => sp.GetService<SomeCustomHandler>().CreateAuthHandler())
    .AddPolicyHandlerFromRegistry(PollyPolicyName.HttpRetry)
    .AddPolicyHandlerFromRegistry(PollyPolicyName.HttpCircuitBreaker);

Also you can define error handling policy via usage of special builders methods of Polly library. In this example policy should be predefined and stored into policy registry service.

public static IServiceCollection AddPollyPolicies(
    this IServiceCollection services, 
    Action<PollyPoliciesOptions> setupAction = null)
{
    var policyOptions = new PollyPoliciesOptions();
    setupAction?.Invoke(policyOptions);

    var policyRegistry = services.AddPolicyRegistry();

    policyRegistry.Add(
        PollyPolicyName.HttpRetry,
        HttpPolicyExtensions
            .HandleTransientHttpError()
            .WaitAndRetryAsync(
                policyOptions.HttpRetry.Count,
                retryAttempt => TimeSpan.FromSeconds(Math.Pow(policyOptions.HttpRetry.BackoffPower, retryAttempt))));

    policyRegistry.Add(
        PollyPolicyName.HttpCircuitBreaker,
        HttpPolicyExtensions
            .HandleTransientHttpError()
            .CircuitBreakerAsync(
                handledEventsAllowedBeforeBreaking: policyOptions.HttpCircuitBreaker.ExceptionsAllowedBeforeBreaking,
                    durationOfBreak: policyOptions.HttpCircuitBreaker.DurationOfBreak));

    return services;
}
Middlemost answered 13/5, 2019 at 11:54 Comment(0)
G
25

Actually I'm not using automatic decompression but the way to achieve this is to properly register http client

services.AddHttpClient<MyCustomHttpClient>()
   .ConfigureHttpMessageHandlerBuilder((c) =>
     new HttpClientHandler()
     {
        AutomaticDecompression = System.Net.DecompressionMethods.GZip
     }
   )
   .AddHttpMessageHandler((s) => s.GetService<MyCustomDelegatingHandler>())
Gav answered 8/6, 2018 at 6:19 Comment(3)
Did not work for me . Had to use .ConfigureHttpMessageHandlerBuilder(builder => { builder.PrimaryHandler = new HttpClientHandler() { UseDefaultCredentials = true }; builder.Build(); })Carvelbuilt
More properly use ConfigurePrimaryHttpMessageHandler() methodMiddlemost
The first call to ConfigureHttpMessageHandlerBuilder in your solution does absolutely nothing, that method takes an Action<T> and you're just returning a value which is immediately discarded: learn.microsoft.com/en-us/dotnet/api/…Bike

© 2022 - 2024 — McMap. All rights reserved.