Distinguish timeout from user cancellation

HttpClient has a built-in timeout function (although it is asynchronous, that is, timeouts can be considered orthogonal for the HTTP request function and, thus, handled by universal asynchronous utilities, but this is aloof), and when the timeout is triggered , ll throw a TaskCanceledException (wrapped in an AggregateException ).

TCE contains a CancellationToken , which is equal to CancellationToken.None .

Now, if I provide an HttpClient my CancellationToken and use it to cancel the operation before its end (or timeout), I get the same TaskCanceledException , again with CancellationToken.None .

Is there another way, by looking only at the exception thrown to find out if the timeout cancels the request without making my CancellationToken available to the code that checks for the exception?

PS Could this be a mistake, and the CancellationToken somehow incorrectly fixed to the CancellationToken.None ? In the canceled use of the user case CancellationToken, I would expect TaskCanceledException.CancellationToken to match this user token.

Edit To make the problem more understandable, with access to the original CancellationTokenSource , it is easy to distinguish the timeout and user cancellation:

origCancellationTokenSource.IsCancellationRequested == true

Getting the CancellationToken from the exception, but gives the wrong answer:

((TaskCanceledException) e.InnerException) .CancellationToken.IsCancellationRequested == false

Here's a minimal example , due to popular demand:

 public void foo() { makeRequest().ContinueWith(task => { try { var result = task.Result; // do something with the result; } catch (Exception e) { TaskCanceledException innerException = e.InnerException as TaskCanceledException; bool timedOut = innerException != null && innerException.CancellationToken.IsCancellationRequested == false; // Unfortunately, the above .IsCancellationRequested // is always false, no matter if the request was // cancelled using CancellationTaskSource.Cancel() // or if it timed out } }); } public Task<HttpResponseMessage> makeRequest() { var cts = new CancellationTokenSource(); HttpClient client = new HttpClient() { Timeout = TimeSpan.FromSeconds(10) }; HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "url"); passCancellationTokenToOtherPartOfTheCode(cts); return client.SendAsync(httpRequestMessage, cts.Token); } 
+24
c # timeout task-parallel-library
Oct 01
source share
2 answers

The accepted answer, of course, how this should work theoretically, but, unfortunately, in practice, IsCancellationRequested not reliably set to the token attached to the exception:

HttpClient Request Cancellation - Why is TaskCanceledException.CancellationToken.IsCancellationRequested false?

+5
Mar 30 '15 at 18:01
source share

Yes, they both return the same exception (possibly due to a timeout, using a token as well), but this can be easily understood by doing this:

  catch (OperationCanceledException ex) { if (token.IsCancellationRequested) { return -1; } return -2; } 

so basically, if you click on the exception, but your token will not be canceled, well, that was a normal http timeout

+4
Mar 01 '13 at 2:03
source share



All Articles