2010-11-16 10 views
14

Rozważmy następujący fragment kodu:Jak utworzyć metodę asynchroniczną w C# 4 zgodnie z najlepszymi praktykami?

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

Należy zwrócić Task<string>, wysyłać żądania HTTP POST z niektórych danych, zwrócić wynik z serwera WWW w postaci ciągu znaków i być tak samo skuteczne, jak to możliwe.

  • Czy zauważyłeś jakieś problemy dotyczące przepływu asynchronicznego w powyższym przykładzie?
  • Czy można mieć .Wait() w środku .ContinueWith() w tym przykładzie
  • Czy widzisz inne problemy związane z tym spokojem kodu (na razie zachowując wyjątek)?
+17

Powinieneś zaakceptować odpowiedzi na inne pytania. – Jimmy

+0

Możesz rozważyć zmianę nazwy obiektu zadania, ponieważ istnieje już obiekt Task w .NET 4. Podczas gdy możesz je połączyć, łatwiej będzie po prostu zmienić nomenklatura. –

+0

Mystere Man, nie mam żadnych niestandardowych deklaracji zadań. Typ zadania, którego używam, pochodzi z .NET 4.0 BCL. –

Odpowiedz

3

Jeśli asynchroniczny kod C# 4.0 jest ogromny i brzydki - jest szansa, że ​​jest poprawnie zaimplementowany. Jeśli jest ładna i krótka, najprawdopodobniej nie jest;)

.. choć możesz ją uatrakcyjnić, tworząc metody rozszerzeń w WebRequest, klasy Stream i oczyszczając główną metodę.

P.S.: Mam nadzieję, że wkrótce pojawi się C# 5.0 z nowym słowem kluczowym async i library.

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

+0

Nowe funkcje w C# 5.0 na PDC2010: http://player.microsoftpdc.com/Session/1b127a7d-300e-4385-af8e-ac747fee677a –

+0

+1 za ogromne i brzydkie = poprawne –

+5

Być może masz rację co do "wielkiego i brzydkiego" , ale nie rozumiem, jak to odpowiada na konkretne pytania Griefa. Jestem zaskoczony, że został przyjęty. –

0

Jesteś rację sądząc, że oczekiwania są niepotrzebne - Wynik będzie blokować aż wynikiem jest gotowy.


jednak jeszcze prostszy sposób byłoby go oprzeć się korzystać z przykładów podanych w ParallelExtensionsExtras library.

Zrobili rozszerzeń dla WebClient które robią dokładnie czego szukasz:

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

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

Możesz przeczytać więcej na ten temat w this post on the Parallel Programming with .NET blog.

+0

Dzięki za dane wejściowe. Dlaczego uważasz, że typ "HttpWebRequest" jest oznaczony jako przestarzały? –

+2

'HttpWebRequest' nie jest oznaczony jako przestarzały, a w rzeczywistości' WebClient' używa go. Być może myślisz o [konstruktorze] (http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.httpwebrequest.aspx). To * jest * przestarzałe, ponieważ zamiast tego powinieneś użyć 'WebRequest.Create'. –

+0

Ups! Naprawię to. – porges

Powiązane problemy