2014-05-08 12 views
5

Następujący kod pobiera zawartość z kilku adresów URL asynchronicznie, a gdy tylko jedna zawartość zostanie pobrana dzięki Task.WhenAny, zostanie przetworzona. Ale w przetworzonej części potrzebuję obiektu Identyfikatora. Myślę, że to wyraźniej pokazać kod:jak dodać więcej szczegółów do zadania zwróconego przez HttpClient.GetAsync

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 ! 
      } 
     } 

Tu Kodeksu 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;  
    } 

Odpowiedz

7

Nie sądzę, że „zbudować listę zadań”, „await Task.WhenAny”, " usuń zakończone zadanie z listy "podejście jest bardzo czyste.

Uważam, że mój kod jest zwykle czystszy, gdy cofam się, przyjrzyj się kodowi i napisz nową asynchroniczną metodę, która wykonuje "początkowe" przetwarzanie, a także "przetwarzanie końcowe". Dzięki swoim przykładzie, że to wyglądać mniej więcej tak:

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

omówię to bardziej szczegółowo w przepisie 2.6 moim współbieżności w C# Cookbook.