web-dev-qa-db-ja.com

HttpClient - タスクはキャンセルされましたか?

1つか2つのタスクがあるときはうまく動作しますが、複数のタスクがリストされているときに「タスクはキャンセルされました」というエラーが発生します。

enter image description here

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

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.
}
210
Todd Menier

私のMain()メソッドは戻る前にタスクが完了するのを待っていなかったのでこの問題に遭遇しました、それで私のコンソールプログラムが終了するときTask<HttpResponseMessage> myTaskはキャンセルされていました。

解決策はmyTask.GetAwaiter().GetResult()の中でMain()を呼び出すことです( この答えから )。

15
Ben Hutchison

もう一つの可能​​性は結果がクライアント側で待っていないことです。これは、呼び出しスタック上のいずれかのメソッドが呼び出しの完了を待つためにawaitキーワードを使用しない場合に起こります。

9
Manish

もう1つの理由は、サービス(API)を実行していてサービスにブレークポイントを設定している場合(そしてコードがブレークポイントで止まっている場合です(例:Visual Studioソリューションで Debugging )を実行中)その後、クライアントコードからAPIをヒットします。したがって、サービスコードがブレークポイントで一時停止した場合は、VSでF5を押すだけです。

0
vivek nuna