Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IHttpHandler IsReusable, but is not getting re-used

I have an IHttpHandler which I believe can benefit from re-use, because it is expensive to set up, and is thread-safe. But a new handler is being created for each request. My handler is not being re-used.

Following is my simple test case, without the expensive setup. This simple case demonstrates my problem:

public class MyRequestHandler : IHttpHandler
{
    int nRequestsProcessed = 0;

    public bool IsReusable
    {
        get { return true; }
    }

    public void ProcessRequest(HttpContext context)
    {
        nRequestsProcessed += 1;
        Debug.WriteLine("Requests processed by this handler: " + nRequestsProcessed);
        context.Response.ContentType = "text/plain";
        context.Response.Write("Hello World");
    }
}

Requests processed by this handler: 1
Requests processed by this handler: 1
Requests processed by this handler: 1
Requests processed by this handler: 1... at least 100 times. I never see > 1.

Am I misunderstanding how IsReusable works? Is there something else that can defeat re-use? My handler is being called from a Silverlight application if that makes any difference.

like image 636
Mark Schmucker Avatar asked Oct 06 '22 18:10

Mark Schmucker


2 Answers

IsReusable is not a guarantee.

Just refactor your handler and put all cross-request state into a different class. Clearly separating cross-request state in a web application in best-practice anyway because it is dangerous.

like image 98
usr Avatar answered Oct 13 '22 10:10

usr


If it's thread-safe, then you can go better than reuse anyway.

When IsReusable returns true then:

  1. First an instance of the handler is created.
  2. It's ProcessRequest is called.
  3. It might be put into a pool to use again.

This means it could reduce the repeated set-up cost, but not necessarily (no guarantee) and not completely - if there are several concurrent calls to the same URI, then there'll need to be several such handlers created to handle them at the same time.

The good thing about this approach is that (when the pooling does happen), handlers don't actually have to be thread-safe.

Since yours is though, we can do better in one of two ways.

One, is to put all of your functionality into another class. Then the handler can just be a slim class where ProcessRequest passes through to a static instance of that one.

Similarly, we can do this with your current class using an IHttpHandlerFactory:

public class MyRequestHandlerFactory : IHttpHandlerFactory
{
  private static MyRequestHandler SingletonHandler = new MyRequestHandler();
  IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
  {
    return SingletonHandler;
  }
  void ReleaseHandler(IHttpHandler handler)
  {
    //do nothing
  }
}

With the above class, you can just change the Web.Config to refer to MyRequestHandlerFactory where it currently refers to MyRequestHandler, and it'll work perfectly.

(Unless you're not actually as thread-safe as you thought, in which case - oopsie!)

like image 33
Jon Hanna Avatar answered Oct 13 '22 10:10

Jon Hanna