Is it possible to call HttpListener.GetContext with a timeout?

KFL picture KFL · Feb 8, 2012 · Viewed 9.8k times · Source

According to the HttpListener reference, a call to HttpListener.GetContext will block until it gets a HTTP request from a client.

I wonder if I can specify a timeout so that after the timeout the function will return. I think otherwise it's unreasonable, since you cannot garantee there will be a request to make this function return, then how can one terminate this call?

P.S. I know there is a async version of it (BeginGetContext) BUT the problem remains because the corresponding EndGetContext will block until an HTTP request arrives.

So as a result, there will be always one thread (if you do it multi-threaded) cannot return because it's blocked on waiting for a request.

Am I missing anything?

UPDATE:

I found this link to be useful. I also found that calling HttpListener.Close() actually terminates the waiting threads that created by the BeginGetContext()s. Somehow HttpListener.Close() fires the callbacks that BeginGetContext() registered. So before you do a HttpListener.EndGetContext(), do check if HttpListener has stopped.

Answer

tofo picture tofo · Nov 13, 2013

Also if you want to do line by line in process handling waiting for a limited time the BeginGetContext returns a System.IAsyncResult exposing the AsyncWaitHandle property

var context = listener.BeginGetContext(new AsyncCallback(ListenerCallback), listener);
context.AsyncWaitHandle.WaitOne();

Above blocks the thread until the listener receives something valid as defined by the heders assigned to the listener or terminates due to some exception that terminates the listener thread and returns result back to ListenerCallback.

But the AsyncWaitHandle.WaitOne() can take timeout parameters

// 5 seconds timeout
bool success = context.AsyncWaitHandle.WaitOne(5000, true);

if (success == false)
{
    throw new Exception("Timeout waiting for http request.");
}

The ListenerCallback could contain a call to listener.EndGetContext or just call the listener.EndGetContext in line if no timeout or error indicated by the AsyncWaitHandle

public static void ListenerCallback(IAsyncResult result)
{
    HttpListener listener = (HttpListener) result.AsyncState;
    // Use EndGetContext to complete the asynchronous operation.
    HttpListenerContext context = listener.EndGetContext(result);
    HttpListenerRequest request = context.Request;
    // Get response object.
    HttpListenerResponse response = context.Response;
    // Construct a response. 
    string responseString = "<HTML><BODY> It Works!</BODY></HTML>";
    byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
    // Write to response stream.
    response.ContentLength64 = buffer.Length;
    System.IO.Stream output = response.OutputStream;
    output.Write(buffer,0,buffer.Length);
    // Close the output stream.
    output.Close();
}

Not to forget to tell the listener to listen again using listener.BeginGetContext