使用HttpClient和ContinueWith的Paralell.ForEach

我有一个方法尝试从并行的几个URL下载数据,并返回IEnumerable反序列化类型

该方法如下所示:

  public IEnumerable DownloadContentFromUrls(IEnumerable urls) { var list = new List(); Parallel.ForEach(urls, url => { lock (list) { _httpClient.GetAsync(url).ContinueWith(request => { var response = request.Result; //todo ensure success? response.Content.ReadAsStringAsync().ContinueWith(text => { var results = JObject.Parse(text.Result) .ToObject<IEnumerable>(); list.AddRange(results); }); }); } }); return list; } 

在我的unit testing中(我存根_httpClient返回一组已知的文本)我基本上得到了

序列不包含任何元素

这是因为该方法在任务完成之前返回。

如果我在.ContinueWith()调用结束时添加.Wait(),它会通过,但我确定我在这里滥用了API …

如果你想要一个使用HttpClient.GetAsync方法并行下载的阻塞调用,那么你应该像这样实现它:

 public IEnumerable DownloadContentFromUrls(IEnumerable urls) { var queue = new ConcurrentQueue(); using (var client = new HttpClient()) { Task.WaitAll(urls.Select(url => { return client.GetAsync(url).ContinueWith(response => { var content = JsonConvert.DeserializeObject>(response.Result.Content.ReadAsStringAsync().Result); foreach (var c in content) queue.Enqueue(c); }); }).ToArray()); } return queue; } 

这将创建一个任务数组,每个Url对应一个任务,表示GetAsync / Deserialize操作。 这假设Url返回TContent的Json数组。 空数组或单个成员数组将反序列化精细,但不是单个无数组对象。