title: Efficient forwarding HTTP requests with an IHttpAsyncHandler
body: <p>I'm developing a HTTP front controller, based on the pattern of Martin Fowler (<a href="http://martinfowler.com/eaaCatalog/frontController.html" rel="nofollow">link</a>). In my case the controller has the following responsibilities:
  - Unmarshall encapsulated data
  - Authorize the request
  - Logging
  - Relay / forward the request to another server</p>
  
  <p>The following to possible solutions came to mind:
  - (Synchronous) IHttpHandler, forwarding the request with the WebClient or the HttpWebRequest class
  - (Asynchronous) IHttpListener (non-IIS solution)
  - (Asynchronous) IHttpAsyncHandler</p>
  
  <p>The ideal situation being that the FC can handle a lots of concurrent requests (>10000 TPS) without burning the CPU.</p>
  
  <p>To test the solutions I've created a small framework that has 3 clients making requests, a front controller that sits in the middle and 2 servers that respond to the requests passed by the FC. The framework benchmarks 3 scenario's, firstly it tests with fast responses with small payloads, secondly: fast responses with big payloads (> 100KB) and lastly its tests with slow responses (>3 seconds) and small payloads. </p>
  
  <p>The transactions per seconds (TPS) drops to an ultimate low (&lt;25 TPS) with the last test with the synchronous HTTP handlers. My guess would be this is due the handler blocks the thread when is waiting for a response. To overcome this problem I've started to implement an asynchronous handler (see code below). The problem is, it simple doesn't work. </p>
  
  <p>The last (untested) solution that came to mind is to use the HttpListener class. Guessing that this is more lightweight solution with a fine grain control for concurrency. I've seen a example implementation using the RX-framework by José F. Romaniello (<a href="http://joseoncode.com/2011/06/17/event-driven-http-server-in-c-with-rx-and-httplistener/" rel="nofollow">link</a>).</p>
  
  <p>My question would be this, why doesn't handler code work?, is this the most efficient way to do so? or should I be in favor of the HttpListener solution.</p>
  
  <p>Asynchronous HTTP-handler code: </p>
  
  <pre><code>public class ForwardRequestHandler : IHttpAsyncHandler
  {
      public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
      {
          var uri = GetForwardUriFor(context.Request.Url.PathAndQuery);
  
          var proxy = HttpWebRequest.Create(uri) as HttpWebRequest;
          return proxy.BeginGetResponse(new AsyncCallback(EndProcessRequest), new ForwardedRequestContext(context, proxy));
      }
  
      public void EndProcessRequest(IAsyncResult result)
      {
          var proxy = result.AsyncState as ForwardedRequestContext;
          proxy.TransferResponse(result);
      }
  
      public bool IsReusable
      {
          get { return true; }
      }
  
      public void ProcessRequest(HttpContext context)
      {
          throw new NotSupportedException();
      }
  
      private Uri GetForwardUriFor(string path)
      {
          var loadbalancer = new RoundRobinLoadBalancer();
          var endpoint = loadbalancer.GetRandomEndPoint();
  
          return new Uri(
              string.Format("http://{0}{1}", endpoint, path)
          );
      }
  }
  
  public class ForwardedRequestContext
  {
      private readonly HttpContext context;
      private readonly HttpWebRequest forwarder;
  
      public ForwardedRequestContext(HttpContext context, HttpWebRequest forwarder)
      {
          this.context = context;
          this.forwarder = forwarder;
      }
  
      public void TransferResponse(IAsyncResult ar)
      {
          var response = GetResponse();
  
          var result = forwarder.EndGetResponse(ar);
          response.StatusCode = 200;
          response.ContentType = result.ContentType;
          response.AddHeader("Content-Length", result.ContentLength.ToString());
  
          result.GetResponseStream().CopyTo(response.OutputStream);
          response.Flush();
  
          result.Close();
      }
  
      private HttpResponse GetResponse()
      {
          return context.Response;
      }
  }
  </code></pre>