如何向HttpClient.GetAsync返回的Task添加更多细节

时间:2014-05-08 15:12:45

标签: c# .net asynchronous task-parallel-library

以下代码是异步检索来自多个网址的内容,并且一旦通过Task.WhenAny下载了一个内容,就会对其进行处理。但在处理过的部分,我需要Identifier对象。我认为向您展示代码更清楚:

 var downloadTasks = new List<Task<string>>();

        foreach (var identifier in input.Identifiers)
        {
            string url = BuildUrl(identifier, input.PeriodInYear, input.Interval);

            var data = _webRequest.GetData(url, token);

            downloadTasks.Add(data); // Here I only add the data, but not the Identifier. I thought about using a List<Tuple<Identifier, Task<string>>, but then I can't use it with Task.WhenAny(...)
        }

        while (downloadTasks.Count > 0)
        {
            var finishedDownloadTask = await Task.WhenAny(downloadTasks);
            downloadTasks.Remove(finishedDownloadTask);

            foreach (var content in await finishedDownloadTask)
            {
                // hereI I also need the Identifier object here !
            }
        }

这里是GetData的代码:

public virtual async Task<string> GetData(string uri, CancellationToken token)
    {
        // log removed
        // try catch removed

        string result = string.Empty;

            using (var client = new HttpClient())
            using (var response = await client.GetAsync(uri, token).ConfigureAwait(false))
            {
                if (response.IsSuccessStatusCode)
                    result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                else
                    logger.Error("Unable to retrieve data from the following url: {0} - StatusCode: {1}", uri, response.StatusCode);
            }

        return result;     
    }

1 个答案:

答案 0 :(得分:7)

我不认为“构建任务列表”,“await Task.WhenAny”,“从列表中删除已完成的任务”方法非常干净。

当我退后一步,查看代码并编写一个执行“初始”处理以及“后处理”的新异步方法时,我发现我的代码通常更干净。在您的示例中,它看起来像这样:

async Task GetDataAndPostProcessAsync(Identifier identifier, CancellationToken token)
{
  var url = BuildUrl(identifier, input.PeriodInYear, input.Interval);
  var content = await _webRequest.GetDataAsync(url, token);
  // Use 'content' with 'identifier'
}

...

var tasks = input.Identifiers.Select(identifier =>
    GetDataAndPostProcessAsync(identifier, token)).ToList();
await Task.WhenAll(tasks);

我在C#Cookbook的“我的并发”的配方2.6中详细介绍了这一点。