在 foreach 循环中使用异步等待

Using asyn await in foreach loop

在 foreach 循环中使用 asyc await 是否不正确?我收到 WebException,请求已取消。

以下只是我正在处理的代码的概要。如果不清楚,请告诉我。

using (var client = new HttpClient())
{
    client.BaseAddress = new Uri("https://xxx.xxx.com/");
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    try
    {
        var response = await client.PostAsJsonAsync("customers/xxxx/xxx/documents", requestMessage);

        response.EnsureSuccessStatusCode();
        var returnValue = response.Content.ReadAsAsync<ResponseMessage>();

        var hasDocuments = returnValue.Result.SearchResults.Any();

        if (hasDocuments)
        {
            // HTTP GET
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));

            returnValue.Result.SearchResults.ForEach(async d =>
            {
                response = await client.GetAsync(d.Self + ".pdf");
            });
        }
    }
    catch (Exception ex)
    {
        throw;
    }
}

您没有在 foreach 循环中使用 async/await,而是在 List<T>.ForEach(Action<T>) 中使用 async/await。因为 ForEach 只接受 Action<T> (void return 类型)你的 ForEach(async d => { ... } 被作为 async void 函数处理,因为这是它被传递的唯一方法作为 Action<T>。这使得 ForEach 在移动到下一个项目之前不会等待上一个项目完成,这就是导致错误的原因。

使用普通的 foreach 而不是 List<T>.ForEach 方法,它应该可以正常工作。

    if (hasDocuments)
    {
        // HTTP GET
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));

        foreach (var d in returnValue.Result.SearchResults)
        {
            response = await client.GetAsync(d.Self + ".pdf");  
        };
    }

唯一允许您使用 async d => ... 的情况是当您传递给的函数接受 Func<T,Task> 时(参见 Task.Run 作为示例)。