views:

413

answers:

2

I'm currently developing a custom HttpHandler (for compressing/combining CSS, but that doesn't matter for this question).

I started with a simple reusable=true synchronous HttpHandler like we all know.

Now i'm trying to improve it to an asynchronous handler (as it uses IO functionality and it's used on a very busy website).

My first attempt (and this seems to work ok):

Action<HttpContext> asyncProcessRequest;

public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
    asyncProcessRequest = new Action<HttpContext>(ProcessRequest);
    return asyncProcessRequest.BeginInvoke(context, cb, extraData);
}

public void EndProcessRequest(IAsyncResult result)
{
    asyncProcessRequest.EndInvoke(result);
}

public virtual void ProcessRequest(HttpContext context)
{
    // real work
}

This is a non-reusable httphandler (as from what I read, IsReusable should be false, because this handler has state (the asyncProcessRequest field).

Now I want to make this reusable. So my first thought was to create a dictionary of IAsyncResult / Action like this:

IDictionary<IAsyncResult, Action<HttpContext>> asyncProcessRequests;

public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
    if (asyncProcessRequests == null)
    {
        asyncProcessRequests = new Dictionary<IAsyncResult, Action<HttpContext>>();
    }

    var request = new Action<HttpContext>(ProcessRequest);
    var result = request.BeginInvoke(context, cb, extraData);
    asyncProcessRequests.Add(result, request);
    return result;
}

public void EndProcessRequest(IAsyncResult result)
{
    Action<HttpContext> action;
    if (asyncProcessRequests.TryGetValue(result, out action))
    {
        action.EndInvoke(result);
    }
}

Is this a correct pattern ? or am I way off?

It seems to work (I'm not getting any errors or weird behavior), but before putting this to production, I would like to verify with someone who has more experience than me in writing these Http handlers..

Thanks in advance!

+1  A: 

If I remember correctly IsReusable indicates to ASP.NET that your handler should not be destroyed after processing request and the same instance could be used for processing subsequent requests. I.e. one instance of the handler object does not handle multiple requests simultaneously.

Yaroslav
So it is not destroyed (subsequent requests use the same instance). But it also guarantees that no simultaneous requests are made on the same instance... How does asp.net handle high load then? does it create more instances ? or does it wait for the current request to be finished?
Remco Ros
Since the initialization of your object is very cheap, making it reusable may not be worth the trouble. This makes sense if the creation of the http handler is expensive (for instance, if it has to initialize from a configuration file or whatever).
Lucero
The point in using IHttpAsyncHandler is to return the thread that is assigned to the request back to the thread pool (threads are limited resource).If your http handler is lightweight object and instantiates quickly I think there would not be significant benefit in performance with reusable handler over non-reusable.
Yaroslav
+2  A: 

In general, for the async pattern, you should use the state parameter which you pass into the BeginXxx method as last parameter (you called it extraData).

So you may want to create a helper class holding the (original) extraData as well as whatever additional state you need to handle the request end.

However, in your specific case, I believe that you're not accelerating anything with the use of the async pattern. While it works, it basically only adds overhead, since you're calling a delegate in an async fashion, which does nothing but dispatch a call to the thread pool to handle the call. Therefore, as long as you don't have multiple delegates running simultaneously via async calls, you're not going to benefit much. Since web requests are multithreaded already, I don't think that this will help performance; in the contrary, you run into the risk of threadpool starvation.

Correct and efficient async handling is not easy. You can benefit from it if you're doing inherently async things such as reading data from a file or network connection or when calling external components which support async invocation (such as a web service call or a database).

Lucero
See also http://geekswithblogs.net/SanjayU/archive/2009/01/06/ihttphandler-vs-ihttpasynchandler.aspx
Lucero
So basically what you are saying is, that I should stick with a reusable synchronous handler ?
Remco Ros
Yes, if you're only planning to invoke the delegate asynchronously. If you're doing lengthy file, network (including web requests) or database calls, consider implementing the async pattern, otherwise rather not. See also http://msdn.microsoft.com/en-us/magazine/cc164128.aspx
Lucero
marking as accepted answer. I'm going to stick with a regular handler
Remco Ros