Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pattern for Reusable asynchronous HttpHandler

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!

like image 266
Remco Ros Avatar asked Feb 05 '10 15:02

Remco Ros


2 Answers

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).

like image 127
Lucero Avatar answered Nov 08 '22 03:11

Lucero


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.

like image 20
Yaroslav Avatar answered Nov 08 '22 01:11

Yaroslav