HttpClient
具有内置的超时功能(尽管是异步的,即可以认为超时与http请求功能正交,因此可以由通用异步实用程序处理,但除此之外),当超时开始时,它将抛出TaskCanceledException
(包裹在AggregateException
中)。
TCE包含的CancellationToken
等于CancellationToken.None
。
现在,如果我为HttpClient
提供自己的CancellationToken
并使用它在操作完成(或超时)之前取消操作,我将获得完全相同的TaskCanceledException
,再次使用CancellationToken.None
。
通过只查看抛出的异常,还有一种方法来确定超时是否取消了请求,而不必使自己的CancellationToken
可用于检查异常的代码?
附言难道这是一个错误,并且CancellationToken
被错误地修复为CancellationToken.None
吗?在使用自定义CancellationToken取消的情况下,我希望TaskCanceledException.CancellationToken
等于该自定义标记。
编辑
为了更清楚地说明问题,可以使用原始的CancellationTokenSource
,很容易区分超时和用户取消:
从异常中获取CancellationToken
会给出错误的答案:
由于受欢迎的需求,这里是最小示例: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);
}
最佳答案
可接受的答案当然是理论上应该如何工作,但是不幸的是,在实践中IsCancellationRequested
不会(可靠地)在附加到异常的 token 上设置:
Cancelling an HttpClient Request - Why is TaskCanceledException.CancellationToken.IsCancellationRequested false?
关于c# - 从用户取消中区分超时,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12666922/