区分超时和用户取消



HttpClient有一个内置的超时功能(尽管都是异步的,即超时可以被视为与http请求功能正交,因此由通用异步实用程序处理,但除此之外),当超时开始时,它将抛出一个TaskCanceledException(封装在AggregateException中)。

TCE包含一个等于CancellationToken.NoneCancellationToken

现在,如果我为HttpClient提供了自己的CancellationToken,并在操作完成(或超时)之前使用它来取消操作,那么我会得到完全相同的TaskCanceledException,同样是CancellationToken.None

是否还有一种方法,只查看抛出的异常,就可以判断超时是否取消了请求,而不必让检查异常的代码访问我自己的CancellationToken

附言:这可能是一个错误,CancellationToken被错误地修复为CancellationToken.None吗?在使用自定义CancellationToken取消的情况下,我希望TaskCanceledException.CancellationToken等于该自定义令牌。

编辑为了更清楚地说明问题,通过访问原始CancellationTokenSource,可以很容易地区分超时和用户取消:

origCancellationTokenSource.IsCancelationRequested=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);
}

公认的答案当然是这个在理论上应该如何工作,但不幸的是,在实践中,IsCancellationRequested没有(可靠地)在附加到异常的令牌上设置:

取消HttpClient请求-为什么TaskCanceledException.CancelationToken.IsCancelationRequested为false?

是的,它们都返回相同的异常(可能是因为内部也使用了令牌超时),但这样做很容易发现:

catch (OperationCanceledException ex)
{
if (token.IsCancellationRequested)
{
return -1;
}
return -2;
}

所以基本上,如果你遇到了异常,但你的代币没有被取消,那么这是一个常规的http超时

相关内容

  • 没有找到相关文章

最新更新