Library code snippets
Asynchronous HttpWebRequest
Since there was just a posting on HttpWebRequest and since it just so happens that I've been having fun with that very class today, I though I'd add my two cents regarding this wicked cool type.
I have a collection of URLs, a couple of hundred for example, and need to query each URL to determine if the site still exists and, if so, when it was last modified. Doing this synchronously could take a couple of minutes depending on bandwidth and traffic.
However, by scanning the URLs asynchronously, you can build a much more responsive and user-friendly application.
There are three important points that need to be integrated to completely solve this:
- Scan the list in a new thread so your UI stays responsive.
- Use
HttpWebRequest.BeginGetResponse()to initiate an asynchronous request. - Use
ThreadPool.RegisterWaitForSingleObject()to register a timeout delegate for unresponsive Web requests.
Yo! Hands off the Thread, Man!
Starting up a new thread is very simple using the .NET Framework System.Threading namespace. We create a new thread, mark it to run in the background and kick it off.
Thread t = new Thread(new ThreadStart(ScanSites));
t.IsBackground = true;
t.Start();
As you might guess, the ScanSites method (a custom method shown below) will run under a thread separate from the Windows.Forms UI. The user will be able to interact with the application without noticing the background process chugging along (hopefully).
Reach Out and Touch Someone
A Web request begins its life fairly mundane. You first need to create a new request. The concrete HttpWebRequest.Create() method returns an abstract WebRequest object. You can modify its properties before calling BeginGetResponse() .
The BeginGetResponse() method is typical of many other asychronous kick-off routines: it requires a pointer to a callback routine and a user-defined argument.
private void ScanSites ()
{
// for each URL in the collection...
WebRequest request = HttpWebRequest.Create(uri);
request.Method = "HEAD";
// RequestState is a custom class to pass info
RequestState state = new RequestState(request,data);
IAsyncResult result = request.BeginGetResponse(
new AsyncCallback(UpdateItem),state);
// PLACEHOLDER: See below...
}
private void UpdateItem (IAsyncResult result)
{
// grab the custom state object
RequestState state = (RequestState)result.AsyncState;
WebRequest request = (WebRequest)state.request;
// get the Response
HttpWebResponse response =
(HttpWebResponse )request.EndGetResponse(result);
// process the response...
}
So far, so good. But what's up with the PLACEHOLDER comment? Read on my friend. Read on...
Careful with that Axe Eugene!
Although the WebRequest class has a Timeout property, it is ignored when using asynchronous requests. So we need to set up our own timer to keep an eye on lengthy HTTP calls. If a call takes too long, we should jump in and abort it, probably marking the URL as suspicious (for example, the site is down or no longer exists).
Here's an example. Replace the PLACEHOLDER comment above with the following call. Then add the ScanTimeoutCallback routine somewhere in your class.
ThreadPool.RegisterWaitForSingleObject(
result.AsyncWaitHandle,
new WaitOrTimerCallback(ScanTimeoutCallback),
state,
(30* 1000), // 30 second timeout
true
);
private static void ScanTimeoutCallback (
object state, bool timedOut)
{
if (timedOut)
{
RequestState reqState = (RequestState)state;
if (reqState != null)
reqState.request.Abort();
}
}
Not too hard, ay? We've covered all three points with pretty straighforward code. Multi-threaded programming in Windows.Form is trivial, but required for a good user experience. Sending asynchronous HTTP requests is equally trivial; just remember to construct a custom state object containing all the relevant information you may need within the AsyncCallback. And, finally, remember to abort requests that refuse to complete. A little code goes a long way.
Related articles
Related discussion
-
Buy cheap Xanax overnight. Cheap Xanax. Overnight delivery of Xanax in US no prescription needed. Cheapest Xanax.
by asleymar (0 replies)
-
Buy Soma online without a prescription. Soma drug no prescription. How to get Soma prescription. Soma cod accepted.
by asleymar (0 replies)
-
Cheap online order Fioricet. Cheap discount Fioricet. Offshore Fioricet online. How to buy Fioricet online without a prescription.
by asleymar (0 replies)
-
Buy Ambien no visa without prescription. Not expensive Ambien prescriptions. Ambien no rx. Cod delivery Ambien.
by asleymar (0 replies)
-
Tramadol without doctor rx. Buy Tramadol over the counter cod overnight. Cheap Tramadol cod delivery. Buy Tramadol from mexico online.
by asleymar (0 replies)
Related podcasts
-
Object-Oriented Programming in Ruby
In this episode, I talk with Scott Bellware about object-oriented programming in Ruby, and Ruby's object model. This is taken from a private conversation, and the audio quality suffers at times. Much thanks to Scott for allowing this to be released.This episode of the Alt.NET Podcast is bro...
Steve thanks for the article. It was really helpful. I am working on a project that somehow uses the web request technique. But I'm facing a tough problem, my application is a web scrapping application. The website I'm scrapping has a combo box list and which of course fires a do post back on change. I want to use the web request to raise or fire the event of the do post back with the value I want and extract the web source page. is that possible?
Thanks in Advance, Happy holidays Beheiry
!--removed tag-->Thanks for this article but I have a question concerning making asynchronous http requests. Is it possible to call the same script say [ http://buzzme.com/index.aspx?message=tasty ] three thousand times (3,000) asynchronously to submit different message parameters without it breaking? ... and at the same time getting the response of each request and logging the output somewhere in a db.
!--removed tag-->Thanks for this article but I have a question concerning making asynchronous http requests. Is it possible to call the same script say [ http://buzzme.com/index.aspx?message=tasty ] three thousand times (3,000) asynchronously to submit different message parameters without it breaking? ... and at the same time getting the response of each request and logging the output somewhere in a db.
!--removed tag-->"Careful with that Axe Eugene" - I love that song.
Hi Steven
I've got the following problem and your proposal seems to be the solution:
I want to do a asynchronous Request, where I have to post a large amount of data to some old asp - component. "Asynchronous" means for me to start the posting and imideately continue with my workflow while in background the huge amount of data is posting...
therrefore I call as suggested in msdn - help:
// Start the asynchronous request.
IAsyncResult result = ( IAsyncResult ) httpRequest.BeginGetResponse ( new AsyncCallback ( RespCallback ), state );
// this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
ThreadPool.RegisterWaitForSingleObject (
result.AsyncWaitHandle, new WaitOrTimerCallback ( TimeoutCallback ),
httpRequest, DefaultTimeout, true );
Now I set my breakpoint in the RespCallback() - Method and here'se the problem:
after BeginGetResponse () the process first jumps to RespCallback() and then jumps to RegisterWaitForSingleObject()
So this is not realy asynchronous...
Did I miss something or is this general behaviour ?
after trying your solution (perform this request in an extra thread) I saw that this would be the right way but I have some questions left:
If you start this request in an extra thread, why do you make this request asynchronous ?
I think, asynchronity in this place is achieved by the extra thread which runs in the background
Is there a way to achieve the asynchronity I want without this extra thread (I'm not sure that what I want realy matches the meaning of "asynchronity" used by BeginGetResponse() ... EndGetResponse() ) ?
thanx in advance and nice greetings
Bernd
This thread is for discussions of Asynchronous HttpWebRequest.