HttpClient
具有内置超时功能(尽管都是异步的,即超时可以被认为与 http 请求功能正交,因此可以由通用异步实用程序处理,但除此之外)并且当超时开始时,它会抛出一个TaskCanceledException
(包裹在一个AggregateException
)。
TCE 包含一个CancellationToken
等于CancellationToken.None
。
现在,如果我提供自己的HttpClient
aCancellationToken
并使用它在操作完成(或超时)之前取消操作,我会得到完全相同的TaskCanceledException
,再次使用 a CancellationToken.None
。
有没有办法通过只查看抛出的异常来确定超时是否取消了请求,而不必让我自己CancellationToken
访问检查异常的代码?
PS这可能是一个错误并且CancellationToken
以某种方式错误地修复了CancellationToken.None
吗?在使用自定义 CancellationToken 取消的情况下,我希望TaskCanceledException.CancellationToken
等于该自定义令牌。
编辑
为了使问题更清楚一点,通过访问原始CancellationTokenSource
,很容易区分超时和用户取消:
origCancellationTokenSource.IsCancellationRequested == true
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<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);
}