Search code examples
c#asp.net-corehttpclientcancellationtokensourcecancellation-token

Creating LinkedTokenSource using typed HttpClient


Hello i am trying to understand how can one create a LinkedTokenSource based on the Timeout property set using the typed HttpClient (using IHttpClientFactory) extension and any other CancellationToken(s):

Registration

public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient("someClient",(client)=>
    {
        client.Timeout=Timespan.FromSeconds(15);
    });
}

Usage

public class SomeService
{
    private IHttpClientFactory factory;
    public SomeService(IHttpClientFactory factory)
    {
        this.factory = factory;
    }
    public async Task MethodWithAggreatedToken(CancellationToken token = default)
    {
        CancellationToken additionalToken = token;
        if (additionalToken == default)
        {
            CancellationTokenSource source = new CancellationTokenSource();
            source.CancelAfter(Timespan.FromSeconds(10));
        }
        var client = factory.CreateClient("someService");
        HttpRequestMessage msg = new HttpRequestMessage(.....);
        using (var cts = CancellationTokenSource.CreateLinkedTokenSource(additionalToken,[DI token])
        {
            var response = await client.SendAsync(msg, cts.Token);
            //can i created a linked token?
            //and if not who gets priority : 
            //1.the token set via the  `Timeout` property set in Startup
            //2.the one injected in the `SendAsync`
        }
    }
}

In the case above i want to be able to set a generic Timeout for my typed HttpClient which will be used in many methods.Now i want to know if :

  • There is a way to add additional Token(s) above this general condition thus creating a LinkedTokenSource
  • Who gets priority if i set a CancellationToken in the HttpClient.SendAsync while also declaring the Timeout property in the services.AddHttpClient.

I want to know if i can do composition of tokens and also who gets overwritten (SendAsync or Timeout)


Solution

  • There is a way to add additional Token(s) above this general condition thus creating new LinkedTokenSource(s)

    Yes, you can link as many CancellationTokenSource as you wish. Because the CreateLinkedTokenSource returns a CancellationTokenSource that's why you can use chaining.

    You can also link more than one CancellationTokenSources at the same time by using that overload which accepts params.

    Who gets priority if i set a CancellationToken in the HttpClient.SendAsync while also declaring the Timeout property in the services.AddHttpClient.

    The Remarks of the HttpClient's Timeout clearly states the following:

    The same timeout will apply for all requests using this HttpClient instance. You may also set different timeouts for individual requests using a CancellationTokenSource on a task. Note that only the shorter of the two timeouts will apply.


    EDIT: Reflect to How do you extract token from the HttpClient?

    In short, it is not exposed.

    If you look at the source code of HttpClient (.NET Framework implementation, .NET Core implementation) then you can spot a CancellationTokenSource private field called pendingRequestsCts

    In the SendAsync / SendAsyncCore methods the pendingRequestsCts is linked to the given operation's CancellationToken.

    In case of .NET Framework it is done by a simple CreateLinkedTokenSource call.
    On the other hand in case of .NET Core it is a bit more complicated. The PrepareCancellationTokenSource method contains both the linked CTS and the timeout calculation.