【问题标题】:HttpClient - A task was cancelled?HttpClient - 任务被取消?
【发布时间】:2015-03-21 06:15:49
【问题描述】:

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

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();
}

【问题讨论】:

标签: c# task-parallel-library dotnet-httpclient


【解决方案1】:

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

  1. 在任务完成之前与取消令牌关联的 CancellationTokenSource 上称为 Cancel() 的东西。
  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.
}

【讨论】:

  • 那么什么是可能的解决方案?我有一个类似的问题。 stackoverflow.com/questions/36937328/…
  • @Dimi - 这已经很老了,但我使用的解决方案是将 Timeout 属性设置为更大的值:httpClient.Timeout = TimeSpan.FromMinutes(30)
  • @RQDQ,你这个男人,男人!不使用构造函数为我解决了这个问题。在我的具体情况下,我想要以毫秒为单位的超时。使用TimeSpan.FromMilliseconds(Configuration.HttpTimeout) 而不是new TimeSpan(Configuration.HttpTimeout) 是一种享受。谢谢!
  • @RQDQ httpClient.Timeout = TimeSpan.FromMinutes(30) 不是一个好方法,因为它会阻塞该特定线程 30 分钟,并且也不会到达 HTTP 端点(这是您的主要任务)。此外,如果您的程序在 30 分钟之前完成,那么您最有可能遇到ThreadAbortException。更好的方法是找出 HTTP 端点没有被命中的原因,它可能需要 VPN 或一些受限的网络访问。
  • @AmitUpadhyay 如果调用是awaited,那么没有线程被阻塞。不是 UI 线程,不是线程池线程 其他后台线程,没有。
【解决方案2】:

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

C#≥7.1

您可以make the main method asynchronous 并等待任务。

public static async Task Main(){
    Task<HttpResponseMessage> myTask = sendRequest(); // however you create the Task
    HttpResponseMessage response = await myTask;
    // process the response
}

C#

解决方案是在Main()(来自this answer)中调用myTask.GetAwaiter().GetResult()。

【讨论】:

    【解决方案3】:
    var clientHttp = new HttpClient();
    clientHttp.Timeout = TimeSpan.FromMinutes(30);
    

    以上是等待大请求的最佳方法。 你困惑了大约 30 分钟;这是随机时间,你可以给任何你想要的时间。

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        将@JobaDiniz 的评论推广到答案:

        不要做显而易见的事情并处理 HttpClient 实例,即使代码“看起来正确”:

        async Task<HttpResponseMessage> Method() {
          using (var client = new HttpClient())
            return client.GetAsync(request);
        }
        

        处置HttpClient 实例可能会导致HttpClient 的其他实例启动的以下HTTP 请求被取消!

        C# 的新 RIAA 语法也是如此;稍微不那么明显:

        async Task<HttpResponseMessage> Method() {
          using var client = new HttpClient();
          return client.GetAsync(request);
        }
        

        相反,正确的方法是为您的应用或库缓存HttpClient 的静态实例,然后重复使用它:

        static HttpClient client = new HttpClient();
        
        async Task<HttpResponseMessage> Method() {
          return client.GetAsync(request);
        }
        

        (Async() 请求方法are all thread safe。)

        【讨论】:

          【解决方案6】:

          在我的 .net core 3.1 应用程序中,我遇到了两个问题,内部原因是超时异常。 1,一个是我得到聚合异常,在它的内部异常是超时异常 2、其他情况是任务取消异常

          我的解决办法是

          catch (Exception ex)
                      {
                          if (ex.InnerException is TimeoutException)
                          {
                              ex = ex.InnerException;
                          }
                          else if (ex is TaskCanceledException)
                          {
                              if ((ex as TaskCanceledException).CancellationToken == null || (ex as TaskCanceledException).CancellationToken.IsCancellationRequested == false)
                              {
                                  ex = new TimeoutException("Timeout occurred");
                              }
                          }                
                          Logger.Fatal(string.Format("Exception at calling {0} :{1}", url, ex.Message), ex);
                      }
          

          【讨论】:

          • 应该是ex.InnerException is TaskCanceledException?
          • IsCancellationRequested 也是真的吗?
          【解决方案7】:

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

          所以我想一直使用 async/await 到顶层以避免此类问题很重要。

          【讨论】:

            【解决方案8】:

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

            【讨论】:

              【解决方案9】:

              我使用的是简单调用而不是 async。一旦我添加了await 并创建了方法async,它就开始正常工作了。

              public async Task<T> ExecuteScalarAsync<T>(string query, object parameter = null, CommandType commandType = CommandType.Text) where T : IConvertible
                      {
                          using (IDbConnection db = new SqlConnection(_con))
                          {
                              return await db.ExecuteScalarAsync<T>(query, parameter, null, null, commandType);
                          }
                      }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-10-07
                • 2020-02-12
                • 2019-01-03
                • 2019-01-06
                相关资源
                最近更新 更多