2010-11-16 52 views
14

考慮下面的代碼片段:如何根據最佳實踐創建C#4異步方法?

public static Task<string> FetchAsync() 
{ 
    string url = "http://www.example.com", message = "Hello World!"; 

    var request = (HttpWebRequest)WebRequest.Create(url); 
    request.Method = WebRequestMethods.Http.Post; 

    return Task.Factory.FromAsync<Stream>(request.BeginGetRequestStream, request.EndGetRequestStream, null) 
     .ContinueWith(t => 
     { 
      var stream = t.Result; 
      var data = Encoding.ASCII.GetBytes(message); 
      Task.Factory.FromAsync(stream.BeginWrite, stream.EndWrite, data, 0, data.Length, null, TaskCreationOptions.AttachedToParent) 
       .ContinueWith(t2 => { stream.Close(); }); 
     }) 
     .ContinueWith<string>(t => 
     { 
      var t1 = 
       Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null) 
       .ContinueWith<string>(t2 => 
       { 
        var response = (HttpWebResponse)t2.Result; 
        var stream = response.GetResponseStream(); 
        var buffer = new byte[response.ContentLength > 0 ? response.ContentLength : 0x100000]; 
        var t3 = Task<int>.Factory.FromAsync(stream.BeginRead, stream.EndRead, buffer, 0, buffer.Length, null, TaskCreationOptions.AttachedToParent) 
         .ContinueWith<string>(t4 => 
         { 
          stream.Close(); 
          response.Close(); 
          if (t4.Result < buffer.Length) 
          { 
           Array.Resize(ref buffer, t4.Result); 
          } 
          return Encoding.ASCII.GetString(buffer); 
         }); 
        t3.Wait(); 
        return t3.Result; 
       }); 
      t1.Wait(); 
      return t1.Result; 
     }); 
} 

它應該返回Task<string>,一些數據發送HTTP POST請求,Web服務器從字符串的形式返回結果,並儘可能多儘可能高效。

  • 您是否發現上述示例中關於異步流程的任何問題?
  • 是否可以在這個例子中使用.ContinueWith()內部的.Wait()
  • 您是否看到任何其他的代碼安全問題(暫時擱置異常處理)?
+17

您應該接受其他問題的一些答案 – Jimmy 2010-11-16 14:02:04

+0

您可能會考慮將您的Task對象重命名爲.NET 4中已經有一個Task對象。雖然可以使它們一起工作,但更改您的方法可能更容易命名。 – 2010-11-16 18:08:12

+0

空軍終於男人,我沒有任何自定義任務聲明。我使用的任務類型來自.NET 4.0 BCL。 – 2010-11-16 19:49:06

回答

3

如果異步相關的C#4.0代碼是巨大和醜陋 - 有可能它正確實施。如果它的好和短,那麼很有可能它不是;)

..though,你可能會得到它看起來通過創建WebRequest的擴展方法,Stream類和清理的主要方法更具吸引力。

P.S.:我希望C#5.0與它的新async關鍵字和library將很快被釋放。

參考http://msdn.microsoft.com/en-us/vstudio/async.aspx

+0

PDC2010 C#5.0中的新功能:http://player.microsoftpdc.com/Session/1b127a7d-300e-4385-af8e-ac747fee677a – 2010-11-16 20:13:56

+0

+1對於巨大和醜陋=正確 – 2010-11-16 20:34:37

+5

你可能對「巨大和醜陋」 ,但我不明白這是如何回答悲傷的具體問題。我很驚訝它被接受。 – 2010-11-18 00:37:50

0

你在想,等待被不必要正確的 - 結果將阻塞,直到結果已經準備就緒。


但是,更簡單的方法是使用ParallelExtensionsExtras library中提供的示例作爲基礎。

他們做了擴展WebClient裏面做正是你在找什麼:

static Task<string> FetchAsync() 
{ 
    string url = "http://www.example.com", message = "Hello World!"; 

    return new WebClient().UploadStringTask(url, "POST", message); 
} 

您可以在this post on the Parallel Programming with .NET blog閱讀更多關於它。

+0

感謝您的輸入被接受。你爲什麼認爲'HttpWebRequest'類型被標記爲過時? – 2010-11-16 20:59:19

+2

'HttpWebRequest'沒有標記爲已過時,事實上,'WebClient'使用它。也許你正在考慮[構造函數](http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.httpwebrequest.aspx)。該*已過時,因爲您應該使用'WebRequest.Create'來代替。 – 2010-11-18 00:35:26

+0

糟糕!將解決這個問題。 – porges 2010-11-18 08:58:33