The asynchronous tactic could be used instead, but it’s a little hard-to-try at glance, the same code I do in a few lines synchronous becomes at least three methods and a lot more lines of code. Just go to MSDN and search for HttpWebRequest.BeginGetRequestStream(...) and you’ll see the sample code like this.
var request = WebRequest.CreateHttp("http://www.example.com/data/to/request"); request.Method = "POST"; request.BeginGetRequestStream(AsyncCallbackRequest, request); (...) private void AsyncCallbackRequest(IAsyncResult ar) { HttpWebRequest request = (HttpWebRequest)ar.AsyncState; Stream stream = request.EndGetRequestStream(ar); (...) // manipulate the stream: write data or wahtever request.BeginGetResponse(GetResponseCallback, request); } private void GetResponseCallback(IAsyncResult ar) { HttpWebRequest request = (HttpWebRequest)ar.AsyncState; HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(ar); Stream streamResponse = response.GetResponseStream(); (...) // manipulate the response: read data and parse it }In some scenarios for example in a Silverlight application, we have not available the whole .NET features and unless we use a third party library or another weird or abstract solution, this is the key for sending or receiving HTTP data across the network. If the application must do several types of request involving different formats or data types, then the amount of asynchronous-logic methods might be larger than the actual business-logic for our application and that’s not good for anyone, maintenance is compromised.
So I’ve done a small class that encapsulates all this garbage repetitive code, at the time I fire some custom events which will be listened outside of the class and the real logic to be performed in those event listeners, the code will be clear and focused on the real tasks to be done on it. I show the code here:
public class AsyncWebRequest { private readonly string _uri; public AsyncWebRequest(string uri) { _uri = uri; } public void Start() { var request = WebRequest.CreateHttp(_uri); request.Method = "POST"; var args = new PrepareDataEventArgs { Request = request }; if (PrepareData != null) { PrepareData(this, args); } request.BeginGetRequestStream(AsyncCallbackRequest, request); } public event EventHandler<PrepareDataEventArgs> PrepareData; public event EventHandler<SendDataEventArgs> SendRequest; public event EventHandler<ReceiveDataEventArgs> ReceiveResponse; private void AsyncCallbackRequest(IAsyncResult ar) { HttpWebRequest request = (HttpWebRequest)ar.AsyncState; var args = new SendDataEventArgs(); // End the operation if (SendRequest != null) { SendRequest(this, args); } // only if there's data or data is not empty, write the actual data if (args.Data != null && args.Data.Length > 0) { Stream stream = request.EndGetRequestStream(ar); // Write to the request stream. stream.Write(args.Data, 0, args.Length); // Close the stream stream.Close(); } // Start the asynchronous operation to get the response request.BeginGetResponse(GetResponseCallback, request); } private void GetResponseCallback(IAsyncResult ar) { HttpWebRequest request = (HttpWebRequest)ar.AsyncState; // End the operation HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(ar); Stream streamResponse = response.GetResponseStream(); StreamReader streamRead = new StreamReader(streamResponse); string responseString = streamRead.ReadToEnd(); if (ReceiveResponse != null) { ReceiveResponse(this, new ReceiveDataEventArgs{ Data = responseString }); } // Close the stream object streamResponse.Close(); streamRead.Close(); // Release the HttpWebResponse response.Close(); //Synchronization.Set(); } }This class fires three events, first the PrepareData is fired before the request is modified for getting the stream, this is a constrain imposed by .NET because after this state the request cannot be modified, so this is the event used to set all the header information such as content/type, among others. After having got the request stream and before start getting the response the second event (SendRequest) is fired and here’s the place to set the actual data to send if any, the length must be set too because the buffer might be larger than the actual data to send. Finally, right after the data arrival, ReceiveResponse, the third event, allows us to set a listener in order to process the received data, for example to parse a JSON data. An example on how to use it is shown as follows:
var asweb = new AsyncWebRequest(_postDataurl); asweb.PrepareData += (o, args) => { args.Request.ContentLength = bytes.Length; args.Request.ContentType = "application/x-www-form-urlencoded"; }; asweb.SendRequest += (o, args) => { args.Data = bytes; args.Length = bytes.Length; }; asweb.ReceiveResponse += (o, args) => { var json = JsonValue.Parse(args.Data); (...) }; asweb.Start();I hope this tiny class will help you to deal with web request taking advantage of asynchrony.
No comments:
Post a Comment