区分超时与用户取消
HttpClient
具有内置超时function(尽管全部是异步的,即超时可以被认为是与http请求function正交,因此可以由通用异步实用程序处理,但除此之外)并且当超时启动时,它将抛出TaskCanceledException
(包装在AggregateException
)。
TCE包含一个等于CancellationToken.None
。
现在,如果我向HttpClient
提供我自己的CancellationToken
并使用它取消操作在它完成(或超时)之前,我得到完全相同的TaskCanceledException
,再次使用CancellationToken.None
。
是否还有一种方法, 通过仅查看抛出的exception ,找出超时是否取消了请求,而不必让我自己的CancellationToken
可以访问检查exception的代码?
PS这可能是一个错误,并且CancellationToken
错误地修复了CancellationToken.None
吗? 在取消使用自定义CancellationToken的情况下,我希望TaskCanceledException.CancellationToken
等于该自定义标记。
编辑为了使问题更加清晰,通过访问原始的CancellationTokenSource
,可以很容易地区分超时和用户取消:
origCancellationTokenSource.IsCancellationRequested == true
从exception中获取CancellationToken
虽然给出了错误的答案:
((TaskCanceledException)e.InnerException).CancellationToken.IsCancellationRequested == false
这是一个最小的例子 ,由于受欢迎的需求:
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 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); }
接受的答案肯定是理论上应该如何工作,但遗憾的是,在实践中, IsCancellationRequested
并未(可靠地)设置在附加到exception的令牌上:
取消HttpClient请求 – 为什么TaskCanceledException.CancellationToken.IsCancellationRequested为false?
是的,它们都返回相同的exception(可能是因为内部使用令牌的超时)但是通过这样做可以很容易地找出它:
catch (OperationCanceledException ex) { if (token.IsCancellationRequested) { return -1; } return -2; }
所以基本上如果你遇到exception但你的令牌没有被取消,那么这是一个常规的http超时