2013-08-13 21 views
6

Muszę uczynić następujący kod asynchroniczny i godne zaufania.Jak sprawić, by zwykły WebRequest był asynchroniczny?

Potrzebuję uzyskać wiele danych z serwera WWW, a następnie dane te zostaną wykorzystane do zapełnienia strony xaml w mojej aplikacji.

Potrzebuję więc metody DefLogin(), aby była ona godna polecenia.

Czy to możliwe?

public void DefLogin() 
    { 
     postData = "My Data To Post"; 
     var url = new Uri("Url To Post to", UriKind.Absolute); 
     webRequest = WebRequest.Create(url); 
     webRequest.Method = "POST"; 
     webRequest.ContentType = "text/xml"; 
     webRequest.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), webRequest); 
    } 

    public void GetRequestStreamCallback(IAsyncResult asynchronousResult) 
    { 
     webRequest = (HttpWebRequest)asynchronousResult.AsyncState; 
     Stream postStream = webRequest.EndGetRequestStream(asynchronousResult); 
     byte[] byteArray = Encoding.UTF8.GetBytes(postData); 
     postStream.Write(byteArray, 0, byteArray.Length); 
     postStream.Close(); 
     Debug.WriteLine("Start BEGINGetResponse"); 
     webRequest.BeginGetResponse(new AsyncCallback(GetResponseCallback), webRequest); 
    } 

    public void GetResponseCallback(IAsyncResult asynchronousResult) 
    { 
     try 
     { 
      HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState; 
      HttpWebResponse response; 
      response = (HttpWebResponse)webRequest.EndGetResponse(asynchronousResult); 
      Stream streamResponse = response.GetResponseStream(); 
      StreamReader streamReader = new StreamReader(streamResponse); 
      string Response = streamReader.ReadToEnd(); 
      streamResponse.Close(); 
      streamReader.Close(); 
      response.Close(); 
      if (Response == "") 
      { 
       //show some error msg to the user   
       Debug.WriteLine("ERROR"); 

      } 
      else 
      { 
       //Your response will be available in "Response" 
       Debug.WriteLine(Response); 
      } 
     } 
     catch (WebException) 
     { 
      //error  
     } 
    } 

Widziałem to pytanie na StackOverflow: Converting ordinary Http Post web request with Async and Await, ale nie mogłem zrozumieć odpowiedź prawidłowo.

Proszę, czy ktoś może pomóc? Byłbym bardzo wdzięczny!

Odpowiedz

13

Można użyć TaskFactory.FromAsync do convert APM to TAP, czyniąc wiele maleńkich metod rozszerzenie tak:

public static Task<Stream> GetRequestStreamAsync(this WebRequest request) 
{ 
    return TaskFactory.FromAsync(request.BeginGetRequestStream, request.EndGetRequestStream, null); 
} 

i zrobić to samo dla WebRequest.GetResponse i (jeśli to konieczne) Stream.Write, Stream.Flush itd

Następnie możesz napisać swoją rzeczywistą logikę używając async i await bez żadnych zwrotów:

public async Task DefLoginAsync() 
{ 
    postData = "My Data To Post"; 
    var url = new Uri("Url To Post to", UriKind.Absolute); 
    webRequest = WebRequest.Create(url); 
    webRequest.Method = "POST"; 
    webRequest.ContentType = "text/xml"; 
    using (Stream postStream = await webRequest.GetRequestStreamAsync()) 
    { 
     byte[] byteArray = Encoding.UTF8.GetBytes(postData); 
     await postStream.WriteAsync(byteArray, 0, byteArray.Length); 
     await postStream.FlushAsync(); 
    } 
    try 
    { 
     string Response; 
     using (var response = (HttpWebResponse)await webRequest.GetResponseAsync()); 
     using (Stream streamResponse = response.GetResponseStream()) 
     using (StreamReader streamReader = new StreamReader(streamResponse)) 
     { 
      Response = await streamReader.ReadToEndAsync(); 
     } 
     if (Response == "") 
     { 
      //show some error msg to the user   
      Debug.WriteLine("ERROR"); 

     } 
     else 
     { 
      //Your response will be available in "Response" 
      Debug.WriteLine(Response); 
     } 
    } 
    catch (WebException) 
    { 
     //error  
    } 
} 
+2

Niesamowita odpowiedź. Ten naprawdę zasługuje na więcej kredytów. Z mojego doświadczenia wynika, że ​​metody rozszerzeń powinny wyglądać tak: "return Task .Factory.FromAsync (etc ...)", w przeciwnym razie wystąpi błąd "Połączenie jest niejednoznaczne". Również NIE pomiń funkcji using(): są one bardzo ważne dla upewnienia się, że Twój strumień jest zamknięty przed EndGet ___(). –

Powiązane problemy