title: WCF performance vs simple ASP.NET HttpHandler
body: <p><strong>TL;DR ver</strong> : WCF service behaves (although it seems configured for max throughput on HTTP) 4x slower than a naive ASP.NET handler implementation</p>
  
  <hr>
  
  <p><strong>UPDATE1</strong> :</p>
  
  <p>Switching to release mode and IIS (full not express) 7.5 changed numbers :</p>
  
  <ul>
  <li>ASP.NET : From 15 sec to 6.7 sec</li>
  <li>WCF : From 60 sec to 13.7 sec</li>
  </ul>
  
  <hr>
  
  <p>Long explanation :</p>
  
  <p>I was looking for an efficient way to transfer information fast in an intranet between two different physical machines (Named pipes gets out of question). My communication contract is composed of the following operations :</p>
  
  <pre><code>void SetUserAsState1(int id);
  void SetUserAsState2(int id);
  byte GetUserState(int id);
  </code></pre>
  
  <p>Pretty simple I'd say. I won't take into consideration security, reliability etc. Just sheer performance. And by performance I mean how many req/sec can be sent to the other machine.</p>
  
  <p>I've done tests on my laptop on two scenarios :</p>
  
  <ul>
  <li>An ASP.NET empty website with a generic GetData.ashx handler which can be invoked like <em>http://localhost:1234/GetData.ashx?op=1&amp;id=239</em> (IIS Express has been used)</li>
  <li>A WCF service hosted in IIS (Express) with basicHttpBinding</li>
  </ul>
  
  <p>How did I test? I set up 10 threads and each thread would do 1000 requests to the target and measure the time taken to complete all 10x1000=10,000 requests. </p>
  
  <p>Results? </p>
  
  <ul>
  <li>ASP.NET : 15 sec</li>
  <li>WCF     : 60 sec</li>
  </ul>
  
  <p>Test harness : (no, it's not production quality)</p>
  
  <pre><code>class Program
  {
      private static Service1Client _wcfProxy;
  
      static void Main()
      {
          _wcfProxy = new Service1Client();
          _wcfProxy.GetData(); // warm up proxy and service
          _wcfProxy.GetData(); // make it really warm :P
  
          var threads = new Thread[10];
          for (var cnt = 0; cnt &lt; 10; cnt++)
          {
              //var t = new ThreadStart(TestAspnetHandler); // scenario 1
              var t = new ThreadStart(TestWcfService); // scenario 2
              (threads[cnt] = new Thread(t)).Start();
          }
          var sw = Stopwatch.StartNew();
          foreach (var thread in threads)
          {
              thread.Join();
          }
          sw.Stop();
          Console.WriteLine("Done 10 x 1000 calls in " + sw.Elapsed);
          Console.ReadLine();
      }
  
      private static void TestAspnetHandler()
      {
          var webClient = new WebClient();
          for (var i = 0; i &lt; 1000; i++)
          {
              webClient.DownloadData("http://localhost:1970/GetData.ashx?id=1");
          }
      }
  
      private static void TestWcfService()
      {
          for (var i = 0; i &lt; 1000; i++)
          {
              _wcfProxy.GetData();
          }
      }
  }
  </code></pre>
  
  <p>ASP.NET implementation :</p>
  
  <pre><code>public class GetData : IHttpHandler
  {
      public void ProcessRequest(HttpContext context)
      {
          context.Response.ContentType = "text/plain";
          var id = context.Request.QueryString["id"];
          if (string.IsNullOrEmpty(id))
          {
              context.Response.Write("Hello World");
          }
          else
          {
              var identifier = int.Parse(id);
              context.Response.Write(identifier * 23);
          }
      }
  
      public bool IsReusable { get { return true; } }
  }
  </code></pre>
  
  <p>default 4.0 configuration, no changes</p>
  
  <hr>
  
  <p>WCF contract :</p>
  
  <pre><code>[ServiceContract]
  public interface IService1
  {
      [OperationContract]
      int GetData();
  }
  </code></pre>
  
  <p>and implementation</p>
  
  <pre><code>[ServiceBehavior(
      ConcurrencyMode = ConcurrencyMode.Multiple, 
      InstanceContextMode = InstanceContextMode.Single)]
  public class Service1 : IService1
  {
      public int GetData()
      {
          return 23;
      }
  }
  </code></pre>
  
  <p>and configuration :</p>
  
  <p></p>
  
  <pre><code>&lt;services&gt;
    &lt;service behaviorConfiguration="beh" name="IService1"&gt;
      &lt;endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttp" 
                contract="WcfService1.IService1" /&gt;
    &lt;/service&gt;
  &lt;/services&gt;
  
  &lt;bindings&gt;
    &lt;basicHttpBinding&gt;
      &lt;binding name="basicHttp" allowCookies="false" /&gt;
    &lt;/basicHttpBinding&gt;
  &lt;/bindings&gt;
  
  &lt;behaviors&gt;
    &lt;serviceBehaviors&gt;
      &lt;behavior name="beh"&gt;
        &lt;serviceThrottling maxConcurrentCalls="1000" maxConcurrentInstances="1000" maxConcurrentSessions="1000" /&gt;
        &lt;serviceMetadata httpGetEnabled="true"/&gt;
        &lt;serviceDebug includeExceptionDetailInFaults="false"/&gt;
      &lt;/behavior&gt;
    &lt;/serviceBehaviors&gt;
  &lt;/behaviors&gt;
  &lt;serviceHostingEnvironment multipleSiteBindingsEnabled="true" /&gt;
  </code></pre>
  
  <p></p>
  
  <hr>
  
  <p><strong>I've set the concurency mode to multiple (so they're not sync'ed), single service instantiation, throttling set to high values, dunno if/how can I speed up anymore the WCF service. Is there any change the WCF service will catch up to the ASP.NET one (implemented over HTTP, that is)?</strong></p>