首页 > 解决方案 > C# 异步 REST 查询不起作用:WaitAll 或 WhenAll 结合 .Result 挂起

问题描述

我正在构建一个 C# Winforms 应用程序,并且我有许多 REST 调用要处理。每个电话大约需要 10 秒才能收到答复,所以最后,我的应用程序运行了很长一段时间。主要是花时间等待 REST 服务回答。

我不会挺身而出,因为无论我尝试什么(configureAwait、waitAll 或 whenAll),应用程序都会挂起,或者当我想访问每个任务结果时,它会返回到 Main 方法或挂起。这是我目前拥有的:

我正在建立一个任务列表来填充我的对象:

List<Task> days = new List<Task>();

for (DateTime d = dtStart; d <= dtEnd; d = d.AddDays(1))
{
    if (UseProduct)
    {
        Task _t = AsyncBuildDay(d, Project, Product, fixVersion);
        var t = _t as Task<Day>;
        days.Add(t);
    }
    else
    {
        Task _t = AsyncBuildDay(d, Project, fixVersion);
        var t = _t as Task<Day>;
        days.Add(t);
    }
}

然后我开始等待,直到每个任务完成并构建对象:

Task.WaitAll(days.ToArray());

当我尝试这个时,任务正在等待激活:

var tks = Task.WhenAll(days.ToArray());

在任务(AsyncBuildDay)中异步运行的是对 JIRA 的查询:

private async Task<string> GetResponse(string url)
{
    WebRequest request = WebRequest.Create(url);
    request.Method = "GET";
    request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.Default.GetBytes(JIRAUser + ":" + JIRAPassword));
    request.Credentials = new NetworkCredential(JIRAUser, JIRAPassword);
    WebResponse response = await request.GetResponseAsync().ConfigureAwait(false);
    // Get the stream containing all content returned by the requested server.
    Stream dataStream = response.GetResponseStream();

    // Open the stream using a StreamReader for easy access.
    StreamReader reader = new StreamReader(dataStream);

    // Read the content fully up to the end.
    string json = reader.ReadToEnd();
    return json;
}

现在我想用 .Result 访问我的所有对象,但随后整个代码又冻结了。

foreach (Task<Day> t in days)
{
    dc.colDays.Add(t.Result);
}

我没有等待得到我的对象,我真的对这些东西发疯了。任何想法都非常感谢!

标签: c#rest

解决方案


你把这件事复杂化了。

Task.WhenAll是要走的路;它返回一个新Task的,当提供的任务全部完成时完成。

它也是非阻塞的。

通过await返回Taskby Task.WhenAll,您将其结果解包到一个数组中:

List<Task<Day>> dayTasks = new();
// ...
Day[] days = await Task.WhenAll(dayTasks);

然后,您可以将其添加到dc.colDays

dc.colDays.AddRange(days);

或者如果dc.colDays没有AddRange方法:

foreach (var day in days) dc.colDays.Add(day);

推荐阅读