HttpClient cancellation doesn't kill underlying TCP call

Viewed 2176

I'm trying to set a default timeout for my HttpClient calls to 5 seconds.

I've done this via CancellationTokenSource.

Here's the pertinent bit of code:

var cancellationToken = new CancellationTokenSource();
cancellationToken.CancelAfter(TimeSpan.FromSeconds(5));
var result = _httpClient.SendAsync(request, cancellationToken.Token);

Works as i expected in terms of the calling code getting a "Task was cancelled" error (i tested in a .NET 4.7 console app), but i noticed in Fiddler the request was still running for 1 minute, until it finally gave up:

enter image description here

Can someone explain this behaviour?

I would expect the underlying request to also get cancelled when the cancellation is triggered.

_httpClient is instantiated like: new HttpClient { BaseAddress = baseAddress }

I know there's the the Timeout setting, but not sure if I should be using that or cancellation tokens? My guess is Timeout is for the non-async/await cases?

2 Answers

If anyone is interested, you can try the following approach to applying your own timeout per HttpClient request. It seems to work for me, restricting the SendAsync() to 2 seconds and returning immediately when the timeout occurs:

private async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, TimeSpan? timeout = null)
{
    if (timeout is null)
    {
        return await _httpClient.SendAsync(request);
    }
    else
    {
        using (var cts = new CancellationTokenSource(timeout.Value))
        {
            var sendTask = _httpClient.SendAsync(request);

            while (!sendTask.IsCompleted)
            {
                cts.Token.ThrowIfCancellationRequested();
                await Task.Delay(10).ConfigureAwait(false);
            }

            return await sendTask.ConfigureAwait(false);
        }
    }
}
Related