Table of Contents

HTTP client integration samples

Transient failures are inevitable for HTTP based communication as well. It is not a surprise that many developers use Polly with an HTTP client to make there applications more robust.

Here we have collected some popular HTTP client libraries and show how to integrate them with Polly.

Setting the stage

In the examples below we will register HTTP clients into a Dependency Injection container.

The same resilience strategy will be used each time to keep the samples focused on the HTTP client library integration.

private static ValueTask<bool> HandleTransientHttpError(Outcome<HttpResponseMessage> outcome) => outcome switch
{
    { Exception: HttpRequestException } => PredicateResult.True(),
    { Result.StatusCode: HttpStatusCode.RequestTimeout } => PredicateResult.True(),
    { Result.StatusCode: >= HttpStatusCode.InternalServerError } => PredicateResult.True(),
    _ => PredicateResult.False()
};

private static RetryStrategyOptions<HttpResponseMessage> GetRetryOptions() =>
new()
{
    ShouldHandle = args => HandleTransientHttpError(args.Outcome),
    MaxRetryAttempts = 3,
    BackoffType = DelayBackoffType.Exponential,
    Delay = TimeSpan.FromSeconds(2)
};

Here we create a strategy which will retry the HTTP request if the status code is either 408, greater than or equal to 500, or an HttpRequestException is thrown.

The HandleTransientHttpError method is equivalent to the HttpPolicyExtensions.HandleTransientHttpError method in the App-vNext/Polly.Extensions.Http repository.

With HttpClient

We use the AddResilienceHandler method to register our resilience strategy with the built-in HttpClient.

var services = new ServiceCollection();

// Register a named HttpClient and decorate with a resilience pipeline
services.AddHttpClient(HttpClientName)
        .ConfigureHttpClient(client => client.BaseAddress = BaseAddress)
        .AddResilienceHandler("httpclient_based_pipeline",
            builder => builder.AddRetry(GetRetryOptions()));

using var provider = services.BuildServiceProvider();

// Resolve the named HttpClient
var httpClientFactory = provider.GetRequiredService<IHttpClientFactory>();
var httpClient = httpClientFactory.CreateClient(HttpClientName);

// Use the HttpClient by making a request
var response = await httpClient.GetAsync("/408");
Note

The following packages are required to the above example:

Further reading for HttpClient

With Flurl

Flurl is a URL builder and HTTP client library for .NET.

The named HttpClient registration and its decoration with our resilience strategy are the same as the built-in HttpClient.

Here we create a FlurlClient which uses the decorated, named HttpClient for HTTP requests.

var services = new ServiceCollection();

// Register a named HttpClient and decorate with a resilience pipeline
services.AddHttpClient(HttpClientName)
        .ConfigureHttpClient(client => client.BaseAddress = BaseAddress)
        .AddResilienceHandler("flurl_based_pipeline",
            builder => builder.AddRetry(GetRetryOptions()));

using var provider = services.BuildServiceProvider();

// Resolve the named HttpClient and create a new FlurlClient
var httpClientFactory = provider.GetRequiredService<IHttpClientFactory>();
var flurlClient = new FlurlClient(httpClientFactory.CreateClient(HttpClientName));

// Use the FlurlClient by making a request
var response = await flurlClient.Request("/408").GetAsync();
Note

The following packages are required to the above example:

Further reading for Flurl

With Refit

Refit is an automatic type-safe REST library for .NET.

First let's define the API interface:

public interface IHttpStatusApi
{
    [Get("/408")]
    Task<HttpResponseMessage> GetRequestTimeoutEndpointAsync();
}

Then use the AddRefitClient method to register the interface as a typed HttpClient. Finally we call AddResilienceHandler to decorate the underlying HttpClient with our resilience strategy.

var services = new ServiceCollection();

// Register a Refit generated typed HttpClient and decorate with a resilience pipeline
services.AddRefitClient<IHttpStatusApi>()
        .ConfigureHttpClient(client => client.BaseAddress = BaseAddress)
        .AddResilienceHandler("refit_based_pipeline",
            builder => builder.AddRetry(GetRetryOptions()));

// Resolve the typed HttpClient
using var provider = services.BuildServiceProvider();
var apiClient = provider.GetRequiredService<IHttpStatusApi>();

// Use the Refit generated typed HttpClient by making a request
var response = await apiClient.GetRequestTimeoutEndpointAsync();
Note

The following packages are required to the above example:

Further readings for Refit

With RestSharp

RestSharp is a simple REST and HTTP API Client for .NET.

The named HttpClient registration and its decoration with our resilience strategy are the same as the built-in HttpClient.

Here we create a RestClient which uses the decorated, named HttpClient for HTTP requests.

var services = new ServiceCollection();

// Register a named HttpClient and decorate with a resilience pipeline
services.AddHttpClient(HttpClientName)
        .ConfigureHttpClient(client => client.BaseAddress = BaseAddress)
        .AddResilienceHandler("restsharp_based_pipeline",
            builder => builder.AddRetry(GetRetryOptions()));

using var provider = services.BuildServiceProvider();

// Resolve the named HttpClient and create a RestClient
var httpClientFactory = provider.GetRequiredService<IHttpClientFactory>();
var restClient = new RestClient(httpClientFactory.CreateClient(HttpClientName));

// Use the RestClient by making a request
var request = new RestRequest("/408", Method.Get);
var response = await restClient.ExecuteAsync(request);
Note

The following packages are required to the above example:

Further reading for RestSharp