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:
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?
As Damien said in the comments, HttpClient
re-uses connections as much as possible, hence the reason why the connection is not closed on cancel.
When canceling a request like that, the HttpClient
will just stop sending/receiving data to/from the other end. It will not send anything to inform the other end that it was cancelled. So the timeout you see of 1 minute depends on the behavior of the other end of your connection.
Also, if you want to cancel each request after 5 seconds, you can as well set the Timeout
property of _httpClient
to TimeSpan.FromSeconds(5)
. The behavior will be exactly the same (a TaskCanceledException
will be thrown if the other end doesn't respond within 5 seconds).
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);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With