If the exceptions do not indicate the difference between the two cases, you will need to check with either Task or CancellationToken to see if it has been canceled.
I would lean to the question that Task , which has the IsCanceled property, would return true if an unhandled OperationCanceledException base.SendAsync (with a CancellationToken.ThrowIfCancellationRequested probability inside base.SendAsync ). Something like that...
HttpResponseMessage response = null; Task sendTask = null; try { sendTask = base.SendAsync(request, cancellationToken); await sendTask; } catch (OperationCanceledException ex) { if (!sendTask.IsCancelled) { LogTimeout(...); throw; } }
EDIT
In response to updating the question, I wanted to update my answer. You correctly cancel whether it is specifically requested for the CancellationTokenSource or if it is timed out, will lead to an accurate result. If you decompile the CancellationTokenSource , you will see that for the timeout, it simply sets the Timer callback, which will explicitly call CancellationTokenSource.Cancel when the timeout is reached, so both methods will eventually call the same Cancel method.
I think that if you want to tell the difference, you need to get from the CancellationTokenSource (this is not a sealed class), and then add your own cancellation method that sets a flag so that you know that you explicitly canceled the operation and not give it time.
This is unfortunate, since you will have both your custom cancel method and the original Cancel method, and you will definitely need to use it. You can get away with your custom logic just by hiding the existing Cancel operation with something like this:
class CustomCancellationTokenSource : CancellationTokenSource { public bool WasManuallyCancelled {get; private set;} public new void Cancel() { WasManuallyCancelled = true; base.Cancel(); } }
I think hiding the base method will work, you can give it a chance and find out.
source share