HttpClient-任务已取消?


191

当有一个或两个任务时,它工作正常,但是当我们列出多个任务时,会引发错误“任务已取消”。

在此处输入图片说明

List<Task> allTasks = new List<Task>();
allTasks.Add(....);
allTasks.Add(....);
Task.WaitAll(allTasks.ToArray(), configuration.CancellationToken);


private static Task<T> HttpClientSendAsync<T>(string url, object data, HttpMethod method, string contentType, CancellationToken token)
{
    HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, url);
    HttpClient httpClient = new HttpClient();
    httpClient.Timeout = new TimeSpan(Constants.TimeOut);

    if (data != null)
    {
        byte[] byteArray = Encoding.ASCII.GetBytes(Helper.ToJSON(data));
        MemoryStream memoryStream = new MemoryStream(byteArray);
        httpRequestMessage.Content = new StringContent(new StreamReader(memoryStream).ReadToEnd(), Encoding.UTF8, contentType);
    }

    return httpClient.SendAsync(httpRequestMessage).ContinueWith(task =>
    {
        var response = task.Result;
        return response.Content.ReadAsStringAsync().ContinueWith(stringTask =>
        {
            var json = stringTask.Result;
            return Helper.FromJSON<T>(json);
        });
    }).Unwrap();
}

内部异常怎么说?
RagtimeWilly 2015年

1
为什么您将CancellationTokenas作为参数而不使用它?
Jim Aho

1
我的原因是HttpClient错误处置,例如async Task<HttpResponseMessage> Method(){ using(var client = new HttpClient()) return client.GetAsync(request); }
JobaDiniz

3
对于使用HttpClient@JobaDiniz(带有using())的用户,请停止!原因:aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
Philippe

Answers:


271

TaskCanceledException抛出a的可能原因有2个:

  1. 一些所谓的Cancel()CancellationTokenSource与取消标记任务完成之前有关。
  2. 请求超时,即未在您指定的时间范围内完成HttpClient.Timeout

我的猜测是超时。(如果这是一个明确的取消,您可能会想出来的。)通过检查异常可以更加确定:

try
{
    var response = task.Result;
}
catch (TaskCanceledException ex)
{
    // Check ex.CancellationToken.IsCancellationRequested here.
    // If false, it's pretty safe to assume it was a timeout.
}

3
那么什么是可能的解决方案?我有一个类似的问题。stackoverflow.com/questions/36937328/…–
开发人员

48
@Dimi-这已经很老了,但是我使用的解决方案是将Timeout属性设置为更大的值:httpClient.Timeout = TimeSpan.FromMinutes(30)
RQDQ

2
@RQDQ,你这个男人,男人!不使用构造函数可以为我解决问题。在我的特定情况下,我希望超时以毫秒为单位。使用TimeSpan.FromMilliseconds(Configuration.HttpTimeout)而不是new TimeSpan(Configuration.HttpTimeout)治疗。谢谢!
维克多·乌德

6
@RQDQ httpClient.Timeout = TimeSpan.FromMinutes(30)不是一个好方法,因为它将阻止该特定线程30分钟,并且也不会命中HTTP端点(这是您的主要任务)。另外,如果您的程序在30分钟之前完成,那么您很可能会遇到ThreadAbortException。更好的方法是找出为什么未命中HTTP端点,它可能需要VPN或某些受限制的网络访问。
阿米特·阿帕德哈伊

6
@AmitUpadhyay如果调用了awaited,则没有线程被阻塞。不是UI线程,不是线程池线程,其他后台线程也没有。
托德·梅尼尔

20

我遇到了这个问题,因为我的Main()方法在返回之前没有等待任务完成,因此Task<HttpResponseMessage> myTask当我退出控制台程序时,该方法被取消了。

解决的办法是打电话myTask.GetAwaiter().GetResult()Main()(从这个答案)。


9

另一种可能性是客户端未等待结果。如果调用堆栈上的任何一种方法都没有使用await关键字来等待调用完成,则会发生这种情况。


7
var clientHttp = new HttpClient();
clientHttp.Timeout = TimeSpan.FromMinutes(30);

以上是等待大型请求的最佳方法。您大约30分钟感到困惑;这是随机时间,您可以根据需要提供任何时间。

换句话说,如果请求在30分钟之前得到结果,则请求不会等待30分钟。30分钟表示请求处理时间为30分钟。发生错误“任务已取消”或大数据请求要求时。


0

另一个原因可能是,如果您正在运行服务(API)并在服务中放置一个断点(并且您的代码卡在某个断点处(例如,Visual Studio解决方案显示的是Debugging而不是Running))。然后从客户端代码中访问API。因此,如果服务代码在某个断点处暂停,则只需在VS中按F5。


0

在我的情况下,控制器方法不是异步的,而在控制器方法内部调用的方法是异步的。

因此,我认为一路使用async / await至顶层以避免此类问题很重要。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.