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/

10-14 07:05