2012-09-05 30 views
6

tôi có mã nàythực hiện HttpWebRequest async gọi

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

tôi cần phải làm cho nó đồng bộ. Theo tôi hiểu, điều này có nghĩa là tôi cần thay đổi cuộc gọi thành request.GetRequestStream() thành asychronous.BeginGetRequestStream(). Tôi đã thấy ví dụ this nhưng không thể tìm ra cách áp dụng điều đó cho kịch bản này. Ai đó có thể giúp đỡ?

+0

Bạn đang sử dụng phiên bản .NET nào? Nó tầm thường với .NET 4.5. –

+0

Đó là 4. Tôi chưa thể sử dụng 4.5. –

+0

Vẫn còn khả năng trong 4 phải không? –

Trả lời

12

Các tài liệu có một ví dụ tốt (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

Làm cách nào để thay đổi mã này để trả về một cái gì đó (ví dụ: chuỗi phản hồi) từ GetResponseCallBack cho người gọi ban đầu, vì AsyncCallBack yêu cầu chữ ký để có loại trả lại khoảng trống? –

+0

tôi không biết làm thế nào để làm điều này, và câu trả lời này rõ ràng hơn cho tôi hoàn thành cảm ơn bạn! –

0

bạn có thể hiểu bởi mã này.

Chương trình xác định hai lớp để sử dụng riêng, lớp RequestState, chuyển dữ liệu qua các cuộc gọi không đồng bộ và lớp ClientGetAsync, thực hiện yêu cầu không đồng bộ đến tài nguyên Internet.

Lớp RequestState duy trì trạng thái yêu cầu qua các cuộc gọi đến các phương thức không đồng bộ phục vụ yêu cầu. Nó chứa các cá thể WebRequest và Stream chứa yêu cầu hiện tại đối với tài nguyên và luồng nhận được trong phản hồi, một bộ đệm chứa dữ liệu hiện đang nhận từ tài nguyên Internet và một StringBuilder chứa đáp ứng hoàn chỉnh. Một RequestStateis được chuyển như tham số trạng thái khi phương thức AsyncCallback được đăng ký với WebRequest.BeginGetResponse.

Lớp ClientGetAsync thực hiện yêu cầu không đồng bộ với tài nguyên Internet và ghi phản hồi kết quả vào bảng điều khiển. Nó chứa các phương thức và thuộc tính được mô tả trong danh sách sau.

Thuộc tính allDone chứa phiên bản của lớp ManualResetEvent báo hiệu hoàn thành yêu cầu.

Phương thức Main() đọc dòng lệnh và bắt đầu yêu cầu đối với tài nguyên Internet được chỉ định. Nó tạo ra wreq WebRequest và rs RequestState, gọi BeginGetResponse để bắt đầu xử lý yêu cầu, và sau đó gọi phương thức allDone.WaitOne() để ứng dụng sẽ không thoát cho đến khi cuộc gọi hoàn tất. Sau khi phản hồi được đọc từ tài nguyên Internet, Main() ghi nó vào bàn điều khiển và ứng dụng kết thúc.

Phương thức showusage() viết dòng lệnh mẫu trên bảng điều khiển. Nó được gọi bởi Main() khi không có URI nào được cung cấp trên dòng lệnh.

Phương thức RespCallBack() triển khai phương thức gọi lại không đồng bộ cho yêu cầu Internet. Nó tạo ra cá thể WebResponse chứa đáp ứng từ tài nguyên Internet, nhận luồng phản hồi và sau đó bắt đầu đọc dữ liệu từ luồng không đồng bộ.

Phương thức ReadCallBack() triển khai phương thức gọi lại không đồng bộ để đọc luồng phản hồi. Nó truyền dữ liệu nhận được từ tài nguyên Internet vào thuộc tính ResponseData của cá thể RequestState, sau đó bắt đầu đọc không đồng bộ khác của luồng phản hồi cho đến khi không có thêm dữ liệu được trả về. Khi tất cả dữ liệu đã được đọc, ReadCallBack() đóng luồng phản hồi và gọi phương thức allDone.Set() để chỉ ra rằng toàn bộ đáp ứng có mặt trong 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; 
    }  
} 
Các vấn đề liên quan