2012-09-05 23 views
6

Mam ten kodwykonawcze HttpWebRequest asynchroniczny wzywa

using (var stream = new StreamWriter(request.GetRequestStream(), Encoding)) 
    stream.Write(body.ToString()); 

muszę zrobić to asynchroniczny. O ile rozumiem, oznacza to, że muszę zmienić połączenie na request.GetRequestStream() na asychronous.BeginGetRequestStream(). Widziałem przykład this, ale nie mogę dowiedzieć się, jak zastosować to do tego scenariusza. Czy ktoś może pomóc?

+0

Którą wersję .NET używasz? To jest trywialne z .NET 4.5. –

+0

To 4. Nie mogę jeszcze użyć 4.5. –

+0

Jest nadal możliwe w 4, prawda? –

Odpowiedz

12

Dokumentacja ma dobry przykład (http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.begingetrequeststream(v=vs.100).aspx):

using System; 
using System.Net; 
using System.IO; 
using System.Text; 
using System.Threading; 

class HttpWebRequestBeginGetRequest 
{ 
    private static ManualResetEvent allDone = new ManualResetEvent(false); 
public static void Main(string[] args) 
{ 
    // Create a new HttpWebRequest object. 
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.contoso.com/example.aspx"); 

    request.ContentType = "application/x-www-form-urlencoded"; 

    // Set the Method property to 'POST' to post data to the URI. 
    request.Method = "POST"; 

    // start the asynchronous operation 
    request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), request); 

    // Keep the main thread from continuing while the asynchronous 
    // operation completes. A real world application 
    // could do something useful such as updating its user interface. 
    allDone.WaitOne(); 
} 

private static void GetRequestStreamCallback(IAsyncResult asynchronousResult) 
{ 
    HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState; 

    // End the operation 
    Stream postStream = request.EndGetRequestStream(asynchronousResult); 

    Console.WriteLine("Please enter the input data to be posted:"); 
    string postData = Console.ReadLine(); 

    // Convert the string into a byte array. 
    byte[] byteArray = Encoding.UTF8.GetBytes(postData); 

    // Write to the request stream. 
    postStream.Write(byteArray, 0, postData.Length); 
    postStream.Close(); 

    // Start the asynchronous operation to get the response 
    request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request); 
} 

private static void GetResponseCallback(IAsyncResult asynchronousResult) 
{ 
    HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState; 

    // End the operation 
    HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult); 
    Stream streamResponse = response.GetResponseStream(); 
    StreamReader streamRead = new StreamReader(streamResponse); 
    string responseString = streamRead.ReadToEnd(); 
    Console.WriteLine(responseString); 
    // Close the stream object 
    streamResponse.Close(); 
    streamRead.Close(); 

    // Release the HttpWebResponse 
    response.Close(); 
    allDone.Set(); 
} 
+0

Jak zmienić ten kod, aby zwrócić coś (np. Ciąg odpowiedzi) z GetResponseCallBack do oryginalnego wywołującego, ponieważ AsyncCallBack wymaga podpisu, aby mieć typ zwrotu nieważności? –

+0

Nie miałem pojęcia, jak to zrobić, a ta odpowiedź jest dla mnie bardziej przejrzysta, dziękuję! –

0

można zrozumieć przez ten kod.

Program definiuje dwie klasy na własny użytek, klasę RequestState, która przekazuje dane przez połączenia asynchroniczne, oraz klasę ClientGetAsync, która implementuje asynchroniczne żądanie do zasobu internetowego.

Klasa RequestState zachowuje stan żądania przez wywołania metod asynchronicznych obsługujących żądanie. Zawiera instancje WebRequest i Stream, które zawierają bieżące żądanie do zasobu i strumienia odebranego w odpowiedzi, bufor zawierający dane aktualnie odbierane z zasobu internetowego oraz StringBuilder zawierający pełną odpowiedź. Obiekt RequestState jest przekazywany jako parametr stanu, gdy metoda AsyncCbackback jest zarejestrowana w WebRequest.BeginGetResponse.

Klasa ClientGetAsync implementuje asynchroniczne żądanie do zasobu internetowego i zapisuje wynikową odpowiedź do konsoli. Zawiera metody i właściwości opisane na poniższej liście.

Właściwość allDone zawiera instancję klasy ManualResetEvent, która sygnalizuje zakończenie żądania.

Metoda Main() odczytuje wiersz polecenia i rozpoczyna żądanie dla określonego zasobu internetowego. Tworzy on wrak WebRequest i RequestState rs, wywołuje BeginGetResponse, aby rozpocząć przetwarzanie żądania, a następnie wywołuje metodę allDone.WaitOne(), aby aplikacja nie zakończyła działania, dopóki wywołanie zwrotne nie zostanie zakończone. Po odczytaniu odpowiedzi z zasobu internetowego, Main() zapisuje ją do konsoli i aplikacja się kończy.

Metoda showusage() zapisuje przykładowy wiersz poleceń na konsoli. Jest wywoływana przez Main(), gdy w wierszu poleceń nie podano żadnego URI.

Metoda RespCallBack() implementuje asynchroniczną metodę wywołania zwrotnego dla żądania internetowego. Tworzy instancję WebResponse zawierającą odpowiedź z zasobu internetowego, pobiera strumień odpowiedzi, a następnie rozpoczyna asynchroniczne odczytywanie danych ze strumienia.

Metoda ReadCallBack() implementuje asynchroniczną metodę oddzwaniania do odczytywania strumienia odpowiedzi. Przesyła dane odebrane z zasobu internetowego do właściwości ResponseData instancji RequestState, a następnie rozpoczyna kolejny asynchroniczny odczyt strumienia odpowiedzi, dopóki nie zostaną zwrócone żadne dane. Po odczytaniu wszystkich danych ReadCallBack() zamyka strumień odpowiedzi i wywołuje metodę allDone.Set(), aby wskazać, że cała odpowiedź jest obecna w ResponseData.

using System; 
using System.Net; 
using System.Threading; 
using System.Text; 
using System.IO; 

// The RequestState class passes data across async calls. 
public class RequestState 
{ 
    const int BufferSize = 1024; 
    public StringBuilder RequestData; 
    public byte[] BufferRead; 
    public WebRequest Request; 
    public Stream ResponseStream; 
    // Create Decoder for appropriate enconding type. 
    public Decoder StreamDecode = Encoding.UTF8.GetDecoder(); 

    public RequestState() 
    { 
     BufferRead = new byte[BufferSize]; 
     RequestData = new StringBuilder(String.Empty); 
     Request = null; 
     ResponseStream = null; 
    }  
} 

// ClientGetAsync issues the async request. 
class ClientGetAsync 
{ 
    public static ManualResetEvent allDone = new ManualResetEvent(false); 
    const int BUFFER_SIZE = 1024; 

    public static void Main(string[] args) 
    { 
     if (args.Length < 1) 
     { 
     showusage(); 
     return; 
     } 

     // Get the URI from the command line. 
     Uri httpSite = new Uri(args[0]); 

     // Create the request object. 
     WebRequest wreq = WebRequest.Create(httpSite); 

     // Create the state object. 
     RequestState rs = new RequestState(); 

     // Put the request into the state object so it can be passed around. 
     rs.Request = wreq; 

     // Issue the async request. 
     IAsyncResult r = (IAsyncResult) wreq.BeginGetResponse(
     new AsyncCallback(RespCallback), rs); 

     // Wait until the ManualResetEvent is set so that the application 
     // does not exit until after the callback is called. 
     allDone.WaitOne(); 

     Console.WriteLine(rs.RequestData.ToString()); 
    } 

    public static void showusage() { 
     Console.WriteLine("Attempts to GET a URL"); 
     Console.WriteLine("\r\nUsage:"); 
     Console.WriteLine(" ClientGetAsync URL"); 
     Console.WriteLine(" Example:"); 
     Console.WriteLine("  ClientGetAsync http://www.contoso.com/"); 
    } 

    private static void RespCallback(IAsyncResult ar) 
    { 
     // Get the RequestState object from the async result. 
     RequestState rs = (RequestState) ar.AsyncState; 

     // Get the WebRequest from RequestState. 
     WebRequest req = rs.Request; 

     // Call EndGetResponse, which produces the WebResponse object 
     // that came from the request issued above. 
     WebResponse resp = req.EndGetResponse(ar);   

     // Start reading data from the response stream. 
     Stream ResponseStream = resp.GetResponseStream(); 

     // Store the response stream in RequestState to read 
     // the stream asynchronously. 
     rs.ResponseStream = ResponseStream; 

     // Pass rs.BufferRead to BeginRead. Read data into rs.BufferRead 
     IAsyncResult iarRead = ResponseStream.BeginRead(rs.BufferRead, 0, 
     BUFFER_SIZE, new AsyncCallback(ReadCallBack), rs); 
    } 


    private static void ReadCallBack(IAsyncResult asyncResult) 
    { 
     // Get the RequestState object from AsyncResult. 
     RequestState rs = (RequestState)asyncResult.AsyncState; 

     // Retrieve the ResponseStream that was set in RespCallback. 
     Stream responseStream = rs.ResponseStream; 

     // Read rs.BufferRead to verify that it contains data. 
     int read = responseStream.EndRead(asyncResult); 
     if (read > 0) 
     { 
     // Prepare a Char array buffer for converting to Unicode. 
     Char[] charBuffer = new Char[BUFFER_SIZE]; 

     // Convert byte stream to Char array and then to String. 
     // len contains the number of characters converted to Unicode. 
     int len = 
     rs.StreamDecode.GetChars(rs.BufferRead, 0, read, charBuffer, 0); 

     String str = new String(charBuffer, 0, len); 

     // Append the recently read data to the RequestData stringbuilder 
     // object contained in RequestState. 
     rs.RequestData.Append(
      Encoding.ASCII.GetString(rs.BufferRead, 0, read));   

     // Continue reading data until 
     // responseStream.EndRead returns –1. 
     IAsyncResult ar = responseStream.BeginRead( 
      rs.BufferRead, 0, BUFFER_SIZE, 
      new AsyncCallback(ReadCallBack), rs); 
     } 
     else 
     { 
     if(rs.RequestData.Length>0) 
     { 
      // Display data to the console. 
      string strContent;     
      strContent = rs.RequestData.ToString(); 
     } 
     // Close down the response stream. 
     responseStream.Close();   
     // Set the ManualResetEvent so the main thread can exit. 
     allDone.Set();       
     } 
     return; 
    }  
}