---
title: "Optimally Configuring ASP.NET Core HttpClientFactory - Muhammad Rehan Saeed"
description: "How to optimally configure a HttpClient using the new HttpClientFactory API in ASP.NET Core 2.1 for best performance, usability, resiliency and easy of use."
canonical_url: "https://rehansaeed.com/optimally-configuring-asp-net-core-httpclientfactory/"
last_updated: "2021-04-04T00:00:00+00:00"
meta:
  author: "Muhammad Rehan Saeed"
  keywords: "ASP.NET Core,CorrelationId,HttpClient,HttpClientFactory,Polly"
  "og:description": "How to optimally configure a HttpClient using the new HttpClientFactory API in ASP.NET Core 2.1 for best performance, usability, resiliency and easy of use."
  "og:image": "https://rehansaeed.com/_og/s/o_723524a97b2a3cc3.png"
  "og:image:alt": "Optimally Configuring ASP.NET Core HttpClientFactory - Muhammad Rehan Saeed"
  "og:image:height": "630"
  "og:image:type": image/png
  "og:image:width": "1200"
  "og:title": "Optimally Configuring ASP.NET Core HttpClientFactory"
  "twitter:image": "https://rehansaeed.com/_og/s/o_723524a97b2a3cc3.png"
  "twitter:image:alt": "Optimally Configuring ASP.NET Core HttpClientFactory - Muhammad Rehan Saeed"
---

> Index of every page on this site: [llms.txt](https://rehansaeed.com/llms.txt)

# [Optimally Configuring ASP.NET Core HttpClientFactory](https://rehansaeed.com/optimally-configuring-asp-net-core-httpclientfactory/)

Posted 20 August 2018 and updated 4 April 2021 - **9 min read**

![Microsoft .NET](https://rehansaeed.com/_ipx/f_png&s_2560x1440/images/hero/Microsoft-.NET-1366x768.png)

Update (04 April 2021)

Updated all code for .NET 5 and mentioned Open Telemetry.

Update (20 August 2018)

[Steve Gordon](https://www.stevejgordon.co.uk/) kindly suggested a [further optimisation](https://github.com/RehanSaeed/HttpClientSample/pull/1) to use `ConfigureHttpClient`. I've updated the code below to reflect this.

In this post, I'm going to show how to optimally configure a `HttpClient` using the new [HttpClientFactory](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-2.1) API in ASP.NET Core 2.1. If you haven't already I recommend reading Steve Gordon's [series of blog posts](https://www.stevejgordon.co.uk/introduction-to-httpclientfactory-aspnetcore) on the subject since this post builds on that knowledge. You should also read his post about [Correlation ID's](https://www.stevejgordon.co.uk/asp-net-core-correlation-ids) as I'm making use of that library in this post. The main aims of the code in this post are to:

1. Use the `HttpClientFactory` typed client, I don't know why the ASP.NET team bothered to provide three ways to register a client, the typed client is the one to use. It provides type safety and removes the need for magic strings.
2. Enable GZIP decompression of responses for better performance. Interestingly, the `HttpClient` and ASP.NET Core does not support compression of GZIP requests, only responses. Doing some searching online some time ago suggests that this is an optimisation that is not very common at all, I thought this was pretty unbelievable at the time.
3. The `HttpClient` should time out after the server does not respond after a set amount of time.
4. The `HttpClient` should retry requests which fail due to transient errors.
5. The `HttpClient` should stop performing new requests for a period of time when a consecutive number of requests fail using the circuit breaker pattern. Failing fast in this way helps to protect an API or database that may be under high load and means the client gets a failed response quickly rather than waiting for a time-out.
6. The URL, time-out, retry and circuit breaker settings should be configurable from the `appsettings.json` file.
7. The `HttpClient` should send a `User-Agent` HTTP header telling the server the name and version of the calling application. If the server is logging this information, this can be useful for debugging purposes.
8. The `X-Correlation-ID` HTTP header from the response should be passed on to the request made using the `HttpClient`. This would make it easy to correlate a request across multiple applications.

# Link to this sectionUsage Example

It doesn't really matter what the typed client `HttpClient` looks like, that's not what we're talking about but I include it for context.

```cs
public interface IRocketClient
{
    Task<TakeoffStatus> GetStatus(bool working);
}

public class RocketClient : IRocketClient
{
    private readonly HttpClient httpClient;

    public RocketClient(HttpClient httpClient) => this.httpClient = httpClient;

    public async Task<TakeoffStatus> GetStatus(bool working)
    {
        var response = await this.httpClient.GetAsync(working ? "status-working" : "status-failing");
        response.EnsureSuccessStatusCode();
        return await response.Content.ReadFromJsonAsync<TakeoffStatus>();
    }
}
```

Here is how we register the typed client above with our dependency injection container. All of the meat lives in these three methods. `AddCorrelationId` adds a middleware written by Steve Gordon to handle [Correlation ID's](https://www.stevejgordon.co.uk/asp-net-core-correlation-ids). `AddPolicies` registers a policy registry and the policies themselves (A policy is [Polly's](https://github.com/App-vNext/Polly) way of specifying how you want to deal with errors e.g. using retries, circuit breaker pattern etc.). Finally, we add the typed `HttpClient` but with configuration options, so we can configure it's settings from `appsettings.json`.

```cs
public virtual void ConfigureServices(IServiceCollection services) =>
    services
        .AddDefaultCorrelationId() // Add Correlation ID support to ASP.NET Core
        .AddControllers()
        .Services
        .AddPolicies(this.configuration) // Setup Polly policies.
        .AddHttpClient<IRocketClient, RocketClient, RocketClientOptions>(this.configuration, "RocketClient")
        ...;
```

The `appsettings.json` file below contains the base address for the endpoint we want to connect to, a time-out value of thirty seconds is used if the server is taking too long to respond and policy settings for retries and the circuit breaker.

The retry settings state that after a first failed request, another three attempts will be made (this means you can get up to four requests). There will be an exponentially longer back-off or delay between each request. The first retry request will occur after two seconds, the second after another four seconds and the third occurs after another eight seconds.

The circuit breaker states that it will allow 12 consecutive failed requests before breaking the circuit and throwing `CircuitBrokenException` for every attempted request. The circuit will be broken for thirty seconds.

Generally, my advice is when allowing a high number of exceptions before breaking, use a longer duration of break. When allowing a lower number of exceptions before breaking, keep the duration of break small.

Another possibility I've not tried is to combine these two scenarios, so you have two circuit breakers. The circuit breaker with the lower limit would kick in first but only break the circuit for a short time, if exceptions are no longer thrown, then things go back to normal quickly. If exceptions continue to be thrown, then the other circuit breaker with a longer duration of break would kick in and the circuit would be broken for a longer period of time. I leave implementing this particular scenario to the reader.

You can of course play with these numbers, what you set them to will depend on your application.

```json
{
    "RocketClient": {
        "BaseAddress": "http://example.com",
        "Timeout": "00:00:30"
    },
    "Policies": {
        "HttpCircuitBreaker": {
            "DurationOfBreak": "00:00:30",
            "ExceptionsAllowedBeforeBreaking": 12
        },
        "HttpRetry": {
            "BackoffPower": 2,
            "Count": 3
        }
    }
}
```

# Link to this sectionConfiguring Polly Policies

Below is the implementation for `AddPollyPolicies`. It starts by setting up and reading a configuration section in our `appsettings.json` file of type `PolicyOptions`. Then adds the [PolicyRegistry](https://github.com/App-vNext/Polly/wiki/PolicyRegistry) which is where Polly stores it's policies. Finally, we add a retry and circuit breaker policy and configure them using the settings we've read from the `PolicyOptions`.

```cs
public static class ServiceCollectionExtensions
{
    private const string PoliciesConfigurationSectionName = "Policies";

    public static IServiceCollection AddPolicies(
        this IServiceCollection services,
        IConfiguration configuration,
        string configurationSectionName = PoliciesConfigurationSectionName)
    {
        services.Configure<PolicyOptions>(configuration);
        var policyOptions = configuration.GetSection(configurationSectionName).Get<PolicyOptions>();

        var policyRegistry = services.AddPolicyRegistry();
        policyRegistry.Add(
            PolicyName.HttpRetry,
            HttpPolicyExtensions
                .HandleTransientHttpError()
                .WaitAndRetryAsync(
                    policyOptions.HttpRetry.Count,
                    retryAttempt => TimeSpan.FromSeconds(Math.Pow(policyOptions.HttpRetry.BackoffPower, retryAttempt))));
        policyRegistry.Add(
            PolicyName.HttpCircuitBreaker,
            HttpPolicyExtensions
                .HandleTransientHttpError()
                .CircuitBreakerAsync(
                    handledEventsAllowedBeforeBreaking: policyOptions.HttpCircuitBreaker.ExceptionsAllowedBeforeBreaking,
                    durationOfBreak: policyOptions.HttpCircuitBreaker.DurationOfBreak));

        return services;
    }
}

public static class PolicyName
{
    public const string HttpCircuitBreaker = nameof(HttpCircuitBreaker);
    public const string HttpRetry = nameof(HttpRetry);
}

public class PolicyOptions
{
    public CircuitBreakerPolicyOptions HttpCircuitBreaker { get; set; }
    public RetryPolicyOptions HttpRetry { get; set; }
}

public class CircuitBreakerPolicyOptions
{
    public TimeSpan DurationOfBreak { get; set; } = TimeSpan.FromSeconds(30);
    public int ExceptionsAllowedBeforeBreaking { get; set; } = 12;
}

public class RetryPolicyOptions
{
    public int Count { get; set; } = 3;
    public int BackoffPower { get; set; } = 2;
}
```

Notice that each policy is using the `HandleTransientHttpError` method which tells Polly when to apply the retry and circuit breakers. One important question is, what is a transient HTTP error according to Polly? Well, looking at the [source code](https://github.com/App-vNext/Polly.Extensions.Http/blob/808665304882fb921b1c38cbbd38fcc102229f84/src/Polly.Extensions.Http.Shared/HttpPolicyExtensions.cs) in the `Polly.Extensions.Http` GitHub repository, it looks like they consider any of the below as transient errors:

1. Any `HttpRequestException` thrown. This can happen when the server is down.
2. A response with a status code of `408 Request Timeout`.
3. A response with a status code of `500 Internal Server Error` or above.

# Link to this sectionConfiguring HttpClient

Finally, we can get down to configuring our `HttpClient` itself. The `AddHttpClient` method starts by binding the `TClientOptions` type to a configuration section in `appsettings.json`. `TClientOptions` is a derived type of `HttpClientOptions` which just contains a base address and time-out value. I'll come back to `CorrelationIdDelegatingHandler` and `UserAgentDelegatingHandler` in a moment.

We set the `HttpClientHandler` to be `DefaultHttpClientHandler`. This type just enables Brotli, GZIP and Deflate compression. Finally, we add the retry and circuit breaker policies to the `HttpClient`.

```cs
public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddHttpClient<TClient, TImplementation, TClientOptions>(
        this IServiceCollection services,
        IConfiguration configuration,
        string configurationSectionName)
        where TClient : class
        where TImplementation : class, TClient
        where TClientOptions : HttpClientOptions, new() =>
        services
            .Configure<TClientOptions>(configuration.GetSection(configurationSectionName))
            .AddSingleton<CorrelationIdDelegatingHandler>()
            .AddSingleton<UserAgentDelegatingHandler>()
            .AddHttpClient<TClient, TImplementation>()
            .ConfigureHttpClient(
                (serviceProvider, httpClient) =>
                {
                    var httpClientOptions = serviceProvider
                        .GetRequiredService<IOptions<TClientOptions>>()
                        .Value;
                    httpClient.BaseAddress = httpClientOptions.BaseAddress;
                    httpClient.Timeout = httpClientOptions.Timeout;
                })
            .ConfigurePrimaryHttpMessageHandler(x => new DefaultHttpClientHandler())
            .AddPolicyHandlerFromRegistry(PolicyName.HttpRetry)
            .AddPolicyHandlerFromRegistry(PolicyName.HttpCircuitBreaker)
            .AddHttpMessageHandler<CorrelationIdDelegatingHandler>()
            .AddHttpMessageHandler<UserAgentDelegatingHandler>()
            .Services;
}

public class DefaultHttpClientHandler : HttpClientHandler
{
    public DefaultHttpClientHandler() => this.AutomaticDecompression =
        DecompressionMethods.Brotli |
        DecompressionMethods.Deflate |
        DecompressionMethods.GZip;
}

public class HttpClientOptions
{
    public Uri BaseAddress { get; set; }

    public TimeSpan Timeout { get; set; }
}
```

# Link to this sectionCorrelationIdDelegatingHandler

When I'm making a HTTP request from an API i.e. it's an API to API call and I control both sides, I use the `X-Correlation-ID` HTTP header to trace requests as they move down the stack. The `CorrelationIdDelegatingHandler` is used to take the correlation ID for the current HTTP request and pass it down to the request made in the API to API call. The implementation is pretty simple, it's just setting a HTTP header.

The power comes when you are using something like Application Insights, Kibana or Seq for logging. You can now take the correlation ID for a request and see the logs for it from multiple API's or services. This is really invaluable when you are dealing with a micro services architecture.

```cs
public class CorrelationIdDelegatingHandler : DelegatingHandler
{
    private readonly ICorrelationContextAccessor correlationContextAccessor;
    private readonly IOptions<CorrelationIdOptions> options;

    public CorrelationIdDelegatingHandler(
        ICorrelationContextAccessor correlationContextAccessor,
        IOptions<CorrelationIdOptions> options)
    {
        this.correlationContextAccessor = correlationContextAccessor;
        this.options = options;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        if (!request.Headers.Contains(this.options.Value.RequestHeader))
        {
            request.Headers.Add(this.options.Value.RequestHeader, this.correlationContextAccessor.CorrelationContext.CorrelationId);
        }

        // Else the header has already been added due to a retry.

        return base.SendAsync(request, cancellationToken);
    }
}
```

# Link to this sectionUserAgentDelegatingHandler

It's often useful to know something about the client that is calling your API for logging and debugging purposes. You can use the `User-Agent` HTTP header for this purpose.

The `UserAgentDelegatingHandler` just sets the `User-Agent` HTTP header by taking the API's assembly name and version attributes. You need to set the `Version` and `Product` attributes in your `csproj` file for this to work. The name and version are then placed along with the current operating system into the User-Agent string.

Now the next time you get an error in your API, you'll know the client application that caused it (if it's under your control).

```cs
public class UserAgentDelegatingHandler : DelegatingHandler
{
    public UserAgentDelegatingHandler()
        : this(Assembly.GetEntryAssembly())
    {
    }

    public UserAgentDelegatingHandler(Assembly assembly)
        : this(GetProduct(assembly), GetVersion(assembly))
    {
    }

    public UserAgentDelegatingHandler(string applicationName, string applicationVersion)
    {
        if (applicationName == null)
        {
            throw new ArgumentNullException(nameof(applicationName));
        }

        if (applicationVersion == null)
        {
            throw new ArgumentNullException(nameof(applicationVersion));
        }

        this.UserAgentValues = new List<ProductInfoHeaderValue>()
        {
            new ProductInfoHeaderValue(applicationName.Replace(' ', '-'), applicationVersion),
            new ProductInfoHeaderValue($"({Environment.OSVersion})"),
        };
    }

    public UserAgentDelegatingHandler(List<ProductInfoHeaderValue> userAgentValues) =>
        this.UserAgentValues = userAgentValues ?? throw new ArgumentNullException(nameof(userAgentValues));

    public List<ProductInfoHeaderValue> UserAgentValues { get; set; }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        if (!request.Headers.UserAgent.Any())
        {
            foreach (var userAgentValue in this.UserAgentValues)
            {
                request.Headers.UserAgent.Add(userAgentValue);
            }
        }

        // Else the header has already been added due to a retry.

        return base.SendAsync(request, cancellationToken);
    }

    private static string GetProduct(Assembly assembly) =>
        assembly.GetCustomAttribute<AssemblyProductAttribute>().Product;

    private static string GetVersion(Assembly assembly) =>
        assembly.GetCustomAttribute<AssemblyFileVersionAttribute>().Version;
}
```

```xml
<PropertyGroup Label="Package">
  <Version>1.0.0</Version>
  <Product>My Application</Product>
  <!-- ... -->
</PropertyGroup>
```

# Link to this sectionOpen Telemetry

Setting the `X-Correlation-ID` and `User-Agent` HTTP headers are useful things to do but there is a new set of HTTP headers which come under the Open Telemetry standard which not only replace them but also add additional functionality. You can read more about [Open Telemetry](https://rehansaeed.com/deep-dive-into-open-telemetry-for-net/) in my [series of blog posts](https://rehansaeed.com/deep-dive-into-open-telemetry-for-net/) on the subject.

# Link to this sectionSample GitHub Project

I realize that was a lot of boilerplate code to write. It was difficult to write this as more than one blog post. To aid in digestion, I've created a [GitHub sample project](https://github.com/RehanSaeed/HttpClientSample) with the full working code.

The sample project contains two API's. One makes a HTTP request to the other. You can pass a query argument to decide whether the callee API will fail or not and try out the retry and circuit breaker logic. Feel free to play with the configuration in `appsettings.json` and see what options work best for your application.

## Web Mentions

[What's this?](https://en.wikipedia.org/wiki/Webmention)

### 0 Linked

### 0 Replies

## GitHub Comments

### 11 Comments

[Comment on GitHub](https://github.com/RehanSaeed/rehansaeed.github.io/issues/99)

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

### [RehanSaeed](https://github.com/RehanSaeed)

Owner

12 May 2020

[![Frank Alvarez](https://camo.githubusercontent.com/e2fba15b3f000b143672059250355def7d01d682660b8775ac8876c4ad69d8ea/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f38613939376466336331313739626661326334626662373036613464623631313f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/e2fba15b3f000b143672059250355def7d01d682660b8775ac8876c4ad69d8ea/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f38613939376466336331313739626661326334626662373036613464623631313f733d393626643d6d6d26723d67) **Frank Alvarez** commented on **2018-08-31 02:33:45**

Where Nice article, but where are you using `IHttpClientFactory`? Shouldn't `RocketClient` be injecting `IHttpClientFactory` instead of `HttpClient`?

Thanks

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

### [RehanSaeed](https://github.com/RehanSaeed)

Owner

12 May 2020

[![Muhammad Rehan Saeed](https://camo.githubusercontent.com/8a07049df41b8a3839a3f4342f09ea8e6e7fa0065667687f04beca2d088a1dca/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f32623266393030653361633066353535316462646537323864336262343935343f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/8a07049df41b8a3839a3f4342f09ea8e6e7fa0065667687f04beca2d088a1dca/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f32623266393030653361633066353535316462646537323864336262343935343f733d393626643d6d6d26723d67) **[Muhammad Rehan Saeed](https://rehansaeed.com/)** commented on **2018-08-31 09:27:56**

> Where Nice article, but where are you using `IHttpClientFactory`? Shouldn't `RocketClient` be injecting `IHttpClientFactory` instead of `HttpClient`?
>
> Thanks

`IHttpClientFactory` is kind of hidden away from you, you don't need to deal with it. You only need to provide some configuration for it and then consume the `HttpClient` it produces which gets injected into your typed client. This makes it much easier to use.

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

### [RehanSaeed](https://github.com/RehanSaeed)

Owner

12 May 2020

[![Stan](https://camo.githubusercontent.com/5477507c5af1388b22cf5d1d9fca65d1f2f98199040ed866c94297d4872a46da/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f34356461663361316131626564323264356135346561343265346433633931343f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/5477507c5af1388b22cf5d1d9fca65d1f2f98199040ed866c94297d4872a46da/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f34356461663361316131626564323264356135346561343265346433633931343f733d393626643d6d6d26723d67) **Stan** commented on **2018-08-31 11:24:09**

Great article, thank you! Would it make sense to add a 3rd `DelegatingHandler`, to give the Receiver a way to detect the retries from the Polly policies? Something along the lines of [this](https://github.com/dotnet-architecture/eShopOnContainers/blob/dev/src/Web/WebMVC/Infrastructure/HttpClientRequestIdDelegatingHandler.cs).

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

### [RehanSaeed](https://github.com/RehanSaeed)

Owner

12 May 2020

[![James](https://camo.githubusercontent.com/3799ae33e89dc81700a6d0d684e67da4aa6e5eece09fa1e9fee807086a7b07a6/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f66313936373566363137356462653337363334373835653531353239373630613f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/3799ae33e89dc81700a6d0d684e67da4aa6e5eece09fa1e9fee807086a7b07a6/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f66313936373566363137356462653337363334373835653531353239373630613f733d393626643d6d6d26723d67) **James** commented on **2018-09-04 11:38:59**

Thank you for the post, very informative, could you recommend a way that we could add a `RefreshTokenDelegateHandler` to the registration which could be configured per typed client?

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

### [RehanSaeed](https://github.com/RehanSaeed)

Owner

12 May 2020

[![Muhammad Rehan Saeed](https://camo.githubusercontent.com/8a07049df41b8a3839a3f4342f09ea8e6e7fa0065667687f04beca2d088a1dca/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f32623266393030653361633066353535316462646537323864336262343935343f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/8a07049df41b8a3839a3f4342f09ea8e6e7fa0065667687f04beca2d088a1dca/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f32623266393030653361633066353535316462646537323864336262343935343f733d393626643d6d6d26723d67) **[Muhammad Rehan Saeed](https://rehansaeed.com/)** commented on **2018-09-21 09:44:28**

> Great article, thank you! Would it make sense to add a 3rd `DelegatingHandler`, to give the Receiver a way to detect the retries from the Polly policies? Something along the lines of [this](https://github.com/dotnet-architecture/eShopOnContainers/blob/dev/src/Web/WebMVC/Infrastructure/HttpClientRequestIdDelegatingHandler.cs).

`X-Correlation-ID` and `X-Request-ID` are the same thing, just different names because there is no standard.

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

### [RehanSaeed](https://github.com/RehanSaeed)

Owner

12 May 2020

[![Muhammad Rehan Saeed](https://camo.githubusercontent.com/8a07049df41b8a3839a3f4342f09ea8e6e7fa0065667687f04beca2d088a1dca/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f32623266393030653361633066353535316462646537323864336262343935343f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/8a07049df41b8a3839a3f4342f09ea8e6e7fa0065667687f04beca2d088a1dca/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f32623266393030653361633066353535316462646537323864336262343935343f733d393626643d6d6d26723d67) **[Muhammad Rehan Saeed](https://rehansaeed.com/)** commented on **2018-09-21 09:46:09**

> Thank you for the post, very informative, could you recommend a way that we could add a `RefreshTokenDelegateHandler` to the registration which could be configured per typed client?

Yes, using a delegate handler for that purpose is the right way to go. I'm not aware of any libraries that provide that for you, IdentityServer4 might have something if you search for it.

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

### [RehanSaeed](https://github.com/RehanSaeed)

Owner

12 May 2020

[![DFT](https://camo.githubusercontent.com/5bc09760dfd05e14949dd7808a4cdacb2de94e59c6d14eab11637ce18de56843/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f36373665623733616439393630643937386464363166316262353837313739373f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/5bc09760dfd05e14949dd7808a4cdacb2de94e59c6d14eab11637ce18de56843/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f36373665623733616439393630643937386464363166316262353837313739373f733d393626643d6d6d26723d67) **DFT** commented on **2019-02-09 03:28:20**

Thanks, I'm using Polly as a Nuget package with very similar settings and cases. What's the approach here? (Taking into account the maturity and the other several policies offered by Polly).

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

### [RehanSaeed](https://github.com/RehanSaeed)

Owner

12 May 2020

[![Ritesh Koul](https://camo.githubusercontent.com/feb657636251873e286e84721136520e467882cd8befe243b62d95b870f00bcb/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f35373736333434613736373739356265616334393733343036393665363233313f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/feb657636251873e286e84721136520e467882cd8befe243b62d95b870f00bcb/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f35373736333434613736373739356265616334393733343036393665363233313f733d393626643d6d6d26723d67) **Ritesh Koul** commented on **2019-06-20 19:17:39**

Hey Rehan one question how can we create sync policy in Polly for synchronous call to Webapi? Or what would be the right solution to create Polly policy where there is synchronous call to web api?

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

### [RehanSaeed](https://github.com/RehanSaeed)

Owner

12 May 2020

[![Muhammad Rehan Saeed](https://camo.githubusercontent.com/8a07049df41b8a3839a3f4342f09ea8e6e7fa0065667687f04beca2d088a1dca/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f32623266393030653361633066353535316462646537323864336262343935343f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/8a07049df41b8a3839a3f4342f09ea8e6e7fa0065667687f04beca2d088a1dca/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f32623266393030653361633066353535316462646537323864336262343935343f733d393626643d6d6d26723d67) **[Muhammad Rehan Saeed](https://rehansaeed.com/)** commented on **2019-06-21 09:15:10**

> Hey Rehan one question how can we create sync policy in Polly for synchronous call to Webapi? Or what would be the right solution to create Polly policy where there is synchronous call to web api?

Avoid using sync API's. It doesn't make sense to do so when making HTTP requests.

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

### [RehanSaeed](https://github.com/RehanSaeed)

Owner

12 May 2020

[![David I](https://camo.githubusercontent.com/a572b71acf4ce33fdf641b045be9e640fd49b0395a8e7a5359ecfda1dee41595/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f61633365653766333466323038663133313263333836323533386563643738373f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/a572b71acf4ce33fdf641b045be9e640fd49b0395a8e7a5359ecfda1dee41595/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f61633365653766333466323038663133313263333836323533386563643738373f733d393626643d6d6d26723d67) **David I** commented on **2019-11-18 20:25:45**

Hi Rehan, great article. I've followed your example and on the first call everything works fine, but if I make a second call I'm finding that I run a `Cannot access a disposed object. ObjectDisposed_ObjectName_Name` exception when the this line is called in the `SendAsync` function in `CorrelationIdDelegatingHandler`:

```
return base.SendAsync(request, cancellationToken);
```

I'm using ASP.NET Core 2.2, but not sure what I'm missing here?

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

### [RehanSaeed](https://github.com/RehanSaeed)

Owner

12 May 2020

[![Muhammad Rehan Saeed](https://camo.githubusercontent.com/8a07049df41b8a3839a3f4342f09ea8e6e7fa0065667687f04beca2d088a1dca/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f32623266393030653361633066353535316462646537323864336262343935343f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/8a07049df41b8a3839a3f4342f09ea8e6e7fa0065667687f04beca2d088a1dca/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f32623266393030653361633066353535316462646537323864336262343935343f733d393626643d6d6d26723d67) **[Muhammad Rehan Saeed](https://rehansaeed.com/)** commented on **2019-11-29 17:47:02**

> Hi Rehan, great article. I've followed your example and on the first call everything works fine, but if I make a second call I'm finding that I run a `Cannot access a disposed object. ObjectDisposed_ObjectName_Name` exception when the this line is called in the `SendAsync` function in `CorrelationIdDelegatingHandler`:
>
> ```
> return base.SendAsync(request, cancellationToken);
> ```
>
> I'm using ASP.NET Core 2.2, but not sure what I'm missing here?

Sounds like you are reusing a disposed resource. Figure out what the resource is and either stop disposing it the second time or create a new one each time. You probably have the IoC lifetime setup incorrectly.

```json
{"@context":"https://schema.org","@graph":[{"@id":"https://rehansaeed.com/#website","@type":"WebSite","description":"Software Developer at Microsoft, YouTuber, Open Source Contributor and Blogger","inLanguage":"en-GB","name":"Muhammad Rehan Saeed","url":"https://rehansaeed.com/","author":{"@id":"https://rehansaeed.com/#identity"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://rehansaeed.com/?search={search_term_string}"},"query-input":"required name=search_term_string"}],"publisher":{"@id":"https://rehansaeed.com/#publisher"}},{"@id":"https://rehansaeed.com/optimally-configuring-asp-net-core-httpclientfactory/#webpage","@type":"WebPage","dateModified":"2021-04-04T00:00:00+00:00","datePublished":"2018-08-20T00:00:00+00:00","description":"How to optimally configure a HttpClient using the new HttpClientFactory API in ASP.NET Core 2.1 for best performance, usability, resiliency and easy of use.","name":"Optimally Configuring ASP.NET Core HttpClientFactory","url":"https://rehansaeed.com/optimally-configuring-asp-net-core-httpclientfactory/","breadcrumb":{"@id":"https://rehansaeed.com/optimally-configuring-asp-net-core-httpclientfactory/#breadcrumb"},"isPartOf":{"@id":"https://rehansaeed.com/#website"},"potentialAction":[{"@type":"ReadAction","target":["https://rehansaeed.com/optimally-configuring-asp-net-core-httpclientfactory/"]}]},{"@id":"https://rehansaeed.com/#identity","@type":"Person","name":"Muhammad Rehan Saeed","url":"https://rehansaeed.com/about/","image":{"@id":"https://rehansaeed.com/#/schema/image/1"},"sameAs":["https://github.com/RehanSaeed","https://www.linkedin.com/in/muhammad-rehan-saeed","https://stackoverflow.com/users/1212017/muhammad-rehan-saeed","https://www.youtube.com/c/MuhammadRehanSaeed","https://www.twitch.tv/rehansaeeduk"]},{"@id":"https://rehansaeed.com/#publisher","@type":"Organization","logo":"https://rehansaeed.com/images/schema/Publisher-600x60.png","name":"Muhammad Rehan Saeed","url":"https://rehansaeed.com"},{"@id":"https://rehansaeed.com/optimally-configuring-asp-net-core-httpclientfactory/#article","@type":"Article","dateModified":"2021-04-04T00:00:00+00:00","datePublished":"2018-08-20T00:00:00+00:00","description":"How to optimally configure a HttpClient using the new HttpClientFactory API in ASP.NET Core 2.1 for best performance, usability, resiliency and easy of use.","headline":"Optimally Configuring ASP.NET Core HttpClientFactory","inLanguage":"en-GB","url":"https://rehansaeed.com/optimally-configuring-asp-net-core-httpclientfactory/","author":{"@id":"https://rehansaeed.com/#identity"},"image":[{"@type":"ImageObject","url":"https://rehansaeed.com/images/hero/Microsoft-.NET-1366x768.png","caption":"Microsoft .NET","width":"1366","height":"768"}],"isPartOf":{"@id":"https://rehansaeed.com/optimally-configuring-asp-net-core-httpclientfactory/#webpage"},"keywords":["ASP.NET Core","CorrelationId","HttpClient","HttpClientFactory","Polly"],"mainEntityOfPage":{"@id":"https://rehansaeed.com/optimally-configuring-asp-net-core-httpclientfactory/#webpage"},"publisher":{"@id":"https://rehansaeed.com/#publisher"}},{"@id":"https://rehansaeed.com/optimally-configuring-asp-net-core-httpclientfactory/#breadcrumb","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","name":"Blog","item":"https://rehansaeed.com/","position":1},{"@type":"ListItem","name":"Optimally Configuring ASP.NET Core HttpClientFactory","item":"https://rehansaeed.com/optimally-configuring-asp-net-core-httpclientfactory/","position":2}]},{"@id":"https://rehansaeed.com/#/schema/image/1","@type":"ImageObject","contentUrl":"https://rehansaeed.com/images/author/Muhammad-Rehan-Saeed/Logo-512x512.png","inLanguage":"en-GB","url":"https://rehansaeed.com/images/author/Muhammad-Rehan-Saeed/Logo-512x512.png"}]}
```

## Sitemap

See the full [sitemap](https://rehansaeed.com/sitemap.md) for all pages.
