2010-11-16 3 views
14

Si consideri il seguente frammento di codice:Come creare un metodo asincrono in C# 4 secondo le migliori pratiche?

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

deve restituire Task<string>, inviare richiesta HTTP POST con alcuni dati, restituisce un risultato dal web server in una forma di stringa ed essere il più efficiente possibile.

  • Hai riscontrato problemi relativi al flusso asincrono nell'esempio sopra?
  • è ok per avere .Wait() all'interno .ContinueWith() in questo esempio
  • Hai visto altri problemi con questa pace di codice (tenendo da parte la gestione delle eccezioni per ora)?
+17

È necessario accettare alcune risposte dalle altre domande – Jimmy

+0

È possibile prendere in considerazione la possibilità di rinominare l'oggetto Task poiché esiste già un oggetto Task in .NET 4. Mentre è possibile farli funzionare insieme, potrebbe essere più semplice cambiare semplicemente il proprio nomenclatura. –

+0

Mystere Man, non ho nessuna dichiarazione di attività personalizzata. Il tipo di attività che sto usando proviene da .NET 4.0 BCL. –

risposta

3

Se il codice asincrono relativo C# 4.0 è enorme e brutto - c'è una possibilità che è implementato correttamente. Se è bello e breve, molto probabilmente non lo è;)

... anche se è possibile ottenere un aspetto più attraente creando metodi di estensione su WebRequest, classi Stream e pulendo il metodo principale.

P.S.: Spero che C# 5.0 con la sua nuova parola chiave async e library sarà rilasciato a breve.

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

+0

Nuove funzionalità in C# 5.0 su PDC2010: http://player.microsoftpdc.com/Session/1b127a7d-300e-4385-af8e-ac747fee677a –

+0

+1 per enorme e brutto = corretto –

+5

Potresti avere ragione riguardo "enorme e brutto" ma non vedo come questo risponda alle domande concrete di Grief. Sono sorpreso che sia stato accettato. –

0

Sei ragione nel pensare che le attese sono inutili - Risultato bloccherà fino a quando il risultato è pronto.


Tuttavia, un modo ancora più semplice sarebbe quella di basare fuori utilizzare gli esempi forniti nel ParallelExtensionsExtras library.

Hanno fatto le estensioni per i WebClient che fare esattamente quello che stai cercando:

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

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

Si può leggere di più su di esso in this post on the Parallel Programming with .NET blog.

+0

Grazie per l'input. Perché pensi che il tipo 'HttpWebRequest' sia contrassegnato come obsoleto? –

+2

'HttpWebRequest' non è contrassegnato come obsoleto e infatti' WebClient' lo utilizza. Forse stai pensando al [costruttore] (http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.httpwebrequest.aspx). Questo * è * obsoleto, perché si suppone che si usi 'WebRequest.Create'. –

+0

Oops! Risolverà quello – porges