3

I've started using System.Net.Http.HttpClient and it's a great class. I'm at a point where I want to give my program's user the ability to cancel operations, for example if a bunch of HTTP requests take too long to complete. So, naturally, I've come across the CancellationTokenSource class and modified my calls to the async methods of HttpClient to also pass them a CancellationToken. In my UI code I can now "cancel that token", and indeed it interrupts whatever HTTP request was in progress at that point.

What I didn't expect, however, is that this causes the interrupted method to throw the TaskCanceledException exception.

Here's my question : I've looked at the MSDN documentation for HttpClient and I have found no mention of that exception. I suppose that is because it's a common behavior to any async method that takes a CancellationToken, but so far I haven't found much information about that. Can you confirm or infirm my supposition, and point me to the relevant documentation ?

My "real question" is whether I'm using the CancellationToken mechanism right, meaning, is that exception supposed to happen, or am I doing something wrong ?

If that exception is supposed to happen, and if it is a mechanism I can rely on, then it will simplify my code. Right now, I test my token's IsCancellationRequested property after each call to HttpClient async methods to determine if my methods should proceed or return, but with this exception, all that additional code becomes pointless.

I'm cancelling the token using this statement :

myCancellationTokenSource.Cancel();
Jean Roch
  • 185
  • 14

2 Answers2

1

Is catching TaskCanceledException and checking Task.Canceled a good idea?

In the .Net framework itself when you pass a CancellationToken as a parameter you will get back a TaskCanceledException. I would not go against that and create my own design pattern because people who are familiar with .Net will be familiar with your code.

My guideline is this: The one that cancels the token is the one that should handle the TaskCanceledException, so If you're using a CancellationToken inside your method for your own reasons, go ahead and use a try-catch block. But if you get the token as a parameter, let the exception be thrown.

https://blogs.msdn.microsoft.com/andrewarnottms/2014/03/19/recommended-patterns-for-cancellationtoken/

Don’t throw OperationCanceledException after you’ve completed the work, just because the token was signaled. Return a successful result and let the caller decide what to do next. The caller can’t assume you’re cancellable at a given point anyway so they have to be prepared for a successful result even upon cancellation.

In my opinion, cancellationToken.ThrowIfCancellationRequested() is the easiest way to handle most interactions with the cancellationToken. Then you only need to handle the exception.

Community
  • 1
  • 1
Alex AIT
  • 17,361
  • 3
  • 36
  • 73
  • I think we're on the same page. Do you have any MSDN link regarding the TaskCancelledException as it pertains to HttpClient ? – Jean Roch Aug 19 '18 at 14:54
  • I am not sure they document stuff which they consider as standard... you can always dig trough the sources though. E.g. https://github.com/dotnet/corefx/blob/6b9440735abc9c4e369376bca097766527971a7a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionCloseReadStream.cs#L21 – Alex AIT Aug 19 '18 at 16:38
1

Throwing TaskCanceledException when canceled is the norm for all methods which accept a CancellationToken parameter. That this isn't always documented is (IMO) an oversight.

But at least there are a few docs for the overall pattern, to document the behavior in a general sense:

https://learn.microsoft.com/en-us/dotnet/standard/threading/cancellation-in-managed-threads

https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/task-cancellation

https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-cancel-a-task-and-its-children

Documents also sometimes just mention OperationCanceledException to imply TaskCanceledException, since they are super- and sub-class.

Tim Lovell-Smith
  • 15,310
  • 14
  • 76
  • 93