2012-05-26 71 views
1

我想問一下如何等待多個異步http請求。如何等待多個異步http請求

我的代碼是這樣的:

public void Convert(XDocument input, out XDocument output) 
    { 
     var ns = input.Root.Name.Namespace; 

     foreach (var element in input.Root.Descendants(ns + "a")) 
     { 
      Uri uri = new Uri((string)element.Attribute("href")); 

      var wc = new WebClient(); 
      wc.OpenReadCompleted += ((sender, e) => 
      { 
       element.Attribute("href").Value = e.Result.ToString(); 
      } 
      ); 
      wc.OpenReadAsync(uri); 
     } 

     //I'd like to wait here until above async requests are all completed. 
     output = input; 
    } 

劑量任何人知道一個解決方案?

回答

2

有他描述如何做非阻塞請求的article by Scott Hanselman。滾動到它的末尾,有一個方法public Task<bool> ValidateUrlAsync(string url)

您可以修改它是這樣的(可能是關於響應閱讀更穩健)

public Task<string> GetAsync(string url) 
{ 
    var tcs = new TaskCompletionSource<string>(); 
    var request = (HttpWebRequest)WebRequest.Create(url); 
    try 
    { 
     request.BeginGetResponse(iar => 
     { 
      HttpWebResponse response = null; 
      try 
      { 
       response = (HttpWebResponse)request.EndGetResponse(iar); 
       using(var reader = new StreamReader(response.GetResponseStream())) 
       { 
        tcs.SetResult(reader.ReadToEnd()); 
       }      
      } 
      catch(Exception exc) { tcs.SetException(exc); } 
      finally { if (response != null) response.Close(); } 
     }, null); 
    } 
    catch(Exception exc) { tcs.SetException(exc); } 
    return tsc.Task; 
} 

所以本在手,然後你可以使用這樣的

var urls=new[]{"url1","url2"}; 
var tasks = urls.Select(GetAsync).ToArray(); 
var completed = Task.Factory.ContinueWhenAll(tasks, 
        completedTasks =>{ 
              foreach(var result in completedTasks.Select(t=>t.Result)) 
              { 
               Console.WriteLine(result); 
              } 
             }); 
completed.Wait(); 
//anything that follows gets executed after all urls have finished downloading 

希望這讓你在正確的方向。

PS。這可能很清楚,因爲它可以不使用異步/等待

1

考慮使用continuation passing style。如果你能調整你的轉換方法就是這樣,

public void ConvertAndContinueWith(XDocument input, Action<XDocument> continueWith) 
{ 
    var ns = input.Root.Name.Namespace; 
    var elements = input.Root.Descendants(ns + "a"); 
    int incompleteCount = input.Root.Descendants(ns + "a").Count; 
    foreach (var element in elements) 
    { 
     Uri uri = new Uri((string)element.Attribute("href")); 

     var wc = new WebClient(); 
     wc.OpenReadCompleted += ((sender, e) => 
     { 
      element.Attribute("href").Value = e.Result.ToString(); 
      if (interlocked.Decrement(ref incompleteCount) == 0) 
       // This is the final callback, so we can continue executing. 
       continueWith(input); 
     } 
     ); 
     wc.OpenReadAsync(uri); 
    } 
} 

然後運行該代碼:

XDocument doc = something; 
ConvertAndContinueWith(doc, (finishedDocument) => { 
    // send the completed document to the web client, or whatever you need to do 
});