title: Problem with IHttpAsyncHandler and ASP.NET "Requests Executing" counter
body: <p><h1>Solved:</h1><b>I found the solution to this. </b><s>Not sure why it happens but</s><b> Switching the application pool type to 'classic' from 'integrated' solves the problem. Now the 'Requests Executing' keeps going up, the actual application pool process thread remains low (~31 threads) and the app is <em>very</em> responsive (as it should be).
  <br><br><s>I'm using .Net 2.0 so maybe there is an issue there - tried to google it but no luck.</s>
  </b>
  <hr>
  <b>See <a href="https://stackoverflow.com/questions/6123453/problem-with-ihttpasynchandler-and-asp-net-requests-executing-counter/6128861#6128861">Joe Enzminger's reply for an explanation</a>
  </b>
  <hr>
  Thank you all again.
  <br/><br/><i>ps. the code is used for playing pool (billiards) online - windows (free) version <a href="http://poolrebel.com" rel="nofollow noreferrer">here</a> for anyone curious and brave enough to try :)</i></p>
  
  <hr/>
  
  <p>Hello,</p>
  
  <p>I've implemented an IHttpAsyncHandler that client applications "poll" to wait for server notifications. Notifications are generated by other "activities" on the server and the Async Handler does no work at all.</p>
  
  <p>The execution steps are:</p>
  
  <pre><code>IHttpAsyncHandler.BeginProcessRequest
  
      Create AsyncResult instance and add it to a "registered clients" collection
  
      return the AsyncResult
  </code></pre>
  
  <p><i>...other server activity will generate notifications to be sent to registered clients...</i></p>
  
  <pre><code>AsyncResult.CompleteCall called as a result of the generated notification(s).
  
  IHttpAsyncHandler.EndProcessRequest is called
  
      The notification(s) attached to the AsyncResult are written to the response stream.
  </code></pre>
  
  <p><b>The problem:</b></p>
  
  <p>I've tested this on IIS7 on a VM with Windows Server 2008 SP2 and 1 cpu core. After 12 clients register for notifications (using an HTTP GET on the Async.ashx) the performance is degraded to the point that subsequent clients cannot connect.</p>
  
  <p>When I check the ASP.NET performance counters the "Requests Executing" counter goes up with each client registration and stays at 12 (which appears to be its maximum value - probably a thread pool size per CPU). </p>
  
  <p>I find this very confusing. I though the whole point of async handlers is to free up threads for other connections. It appears that this is not the case so I must be doing something wrong!</p>
  
  <p>Why is ASP.NET consuming a thread while waiting for my AsyncResult to complete? Is this a config issue? Do I need to do something specific to indicate that this is an Async Handler?</p>
  
  <p>Thank you,
  Nikos.</p>
  
  <p><b>Edit: Added code below:</b><br></p>
  
  <pre><code>public class AsyncResult : IAsyncResult
  {
      private AsyncCallback _cb;
      private object _state;
      private ManualResetEvent _event;
      private bool _completed;
      private bool _completedsynchronously;
      private HttpContext _context;
      private byte[] _data;
      private int _datalength;
      private object _lock = new object();
  
      public AsyncWaitResult(AsyncCallback cb, object state, HttpContext context)
      {
          _context = context;
          _cb = cb;
          _state = state;
      }
  
      public void Close()
      {
          if (_event != null)
          {
              _event.Close();
              _event = null;
          }
      }
  
      public HttpContext Context { get { return _context; } }
      public Object AsyncState { get { return _state; } }
      public bool CompletedSynchronously { get { return _completedsynchronously; } }
      public bool IsCompleted { get { return _completed; } }
      public byte[] Data { get { return _data; } }
      public int DataLength { get { return _datalength; } }
  
      public WaitHandle AsyncWaitHandle
      {
          get
          {
              lock (_lock)
              {
                  if (_event == null)
                      _event = new ManualResetEvent(_completed);
                  return _event;
              }
          }
      }
  
      public void CompleteCall(byte[] data, int length, bool completedsynchronously)
      {
          _data = data;
          _datalength = length;
          _completedsynchronously = completedsynchronously;
  
          lock (_lock)
          {
              _completed = true;
              if (_event != null)
                  _event.Set();
          }
  
          if (_cb != null)
              _cb(this);
      }
  }
  
  
  public class Outbound : IHttpAsyncHandler
  {
      public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object state)
      {
              AsyncResult asyncresult = new AsyncResult(cb, state, context);
  
              RegisteredClients.Instance.Add(asyncresult);
  
              return asyncresult;
      }
  
      public void EndProcessRequest(IAsyncResult ar)
      {
          AsyncResult result = (AsyncResult)ar;
          if (result != null)
          {
              result.Context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
              result.Context.Response.ContentType = "application/octet-stream";
              result.Context.Response.AddHeader("Connection", "keep-alive");
  
              if (result.Data != null)
                  result.Context.Response.OutputStream.Write(result.Data, 0, result.DataLength);
  
              result.Close();
          }
      }
  
      public void ProcessRequest(HttpContext context){}
  
      public bool IsReusable { get { return true; } }
  }
  </code></pre>