15.10 Creating Asynchronous Web Requests

 <  Day Day Up  >  

You want to read a Web document asynchronously to avoid making blocking calls.


Technique

Creating an asynchronous Web request requires the use of two callback methods and an object that holds the current state of the read operation. If you recall from Section 15.8, "Using the WebRequest Class for HTTP Communication," the order of steps for a Web request began with creating a request, retrieving a response, and then reading the data contained within the response. The procedure is similar here, but you use callback methods to process the response from the initial request.

Before we look at the necessary callbacks, you need to create a state object to hold intermediary and final results. Although you are more than welcome to use member variables within a class, you must ensure proper synchronization to ensure data integrity. This example creates a state object for each Web request so that the state of the request is tracked from the beginning of the operation to the end. The following code shows the class used to hold the current state of a Web request. The class itself contains just a few member variables , which include a StringBuilder to hold the final results, a byte array to hold intermediary results after each read operation, the initial request object, and the subsequent stream for reading operations:

 
 public class RequestState {     public StringBuilder Content;     public byte[] BufferRead;     public HttpWebRequest Request = null;     public Stream ResponseStream = null;     public RequestState()     {         BufferRead = new byte[1024];         Content = new StringBuilder("");     } } 

The first callback method handles the actual Web response that is called from the WebRequest object. It is within this method that you want to begin reading the associated data. In the following code, you can see that the state object can be acquired from the IAsyncResult parameter. After this step, you create the stream object from the response object similar to the way you did in Recipe 15.8. Finally, you perform an asynchronous call to the BeginRead method defined in the response object. It eventually calls the second callback method when the reading of the data is finished:

 
 private void ResponseCallback(IAsyncResult result) {     // get state object attached to final result     RequestState state = (RequestState) result.AsyncState;     // Get the request and response objects     HttpWebRequest request = state.Request;     HttpWebResponse response = (HttpWebResponse) request.EndGetResponse(result);     // place response stream into state     state.ResponseStream = response.GetResponseStream();     // start reading asynchronously     IAsyncResult iarRead = state.ResponseStream.BeginRead(state.BufferRead,         0, 1024, new AsyncCallback(ReadCallBack), state); } 

The last callback method you have to define is the method used to notify your application that the reading is finished or the supplied buffer is filled. The first step within the method in the following code is to extract the state object from the IAsyncResult , as was done earlier. Next is the call to EndRead , which returns the number of bytes filled into the buffer within the state object. When no more data is available, this method returns a value of , but as long as the number is greater than , you have to repeatedly call the BeginRead method and repeat the process, as shown in the following code:

 
 private void ReadCallBack(IAsyncResult asyncResult) {     // get state and response objects     RequestState state = (RequestState)asyncResult.AsyncState;     // end the reading and get bytes available     int read = state.ResponseStream.EndRead( asyncResult );     if (read > 0)     {         // get buffer data and append to state content result         state.Content.Append( Encoding.ASCII.GetString(state.BufferRead, 0, read ));         // continue with data read         IAsyncResult ar = state.ResponseStream.BeginRead( state.BufferRead,             0, 1024, new AsyncCallback(ReadCallBack), state);     }     else     {         if(state.Content.Length > 1)         {             tbContent.Text = state.Content.ToString();         }         // Close down the response stream         state.ResponseStream.Close();     }     return; } 

The final step is to actually start the process by creating the request. The actual method itself, shown in the following code, does nothing more than create the initial Web request with the URI of the document to receive followed by the creation of the state object that is passed through the different asynchronous callback methods. You then start the whole process by calling the BeginGetResponse method, passing the callback method that will be used and the state object that is then placed in the IAsyncResult parameter of the callback method:

 
 private void btnGo_Click(object sender, System.EventArgs e) {     // create the request and state objects     HttpWebRequest request = (HttpWebRequest)         WebRequest.Create(tbAddress.Text);     RequestState state = new RequestState();     // place request into state object     state.Request = request;     // start the asynchronous call     IAsyncResult res = (IAsyncResult) request.BeginGetResponse(         new AsyncCallback(ResponseCallback), state); } 

Comments

Recipe 15.8 created a WebRequest object to read a document from the Web. The code itself assumed that the data coming in would always come quickly and without interruptions of any kind. In fact, the reading of the data itself isn't even placed within a thread. This type of design, although fine for examples, might lead to problems later. The problem lies in the creation of the request and the subsequent reading of the data within the response object. The methods are all blocking, which means they will not return until the methods have either timed out or have received all the data. If the server that the application is connecting and reading from is slow, or the data itself is fairly large, then the application will appear as if it has hung. Making asynchronous calls to the request and response objects will solve this dilemma, as shown in the technique earlier. By doing so, you are freeing your application to respond to other events that might occur, such as user -interface events on your main thread.

 <  Day Day Up  >  


Microsoft Visual C# .Net 2003
Microsoft Visual C *. NET 2003 development skills Daquan
ISBN: 7508427505
EAN: 2147483647
Year: 2003
Pages: 440

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net