title: Why is my async ASP.NET Web API controller blocking the main thread?
body: <p>I have an ASP.NET Web API controller that I would have <em>thought</em> would operate asynchronously. The controller is designed to sleep 20 seconds for the first request, but service any subsequent requests immediately. So my anticipated timeline would be something like:</p>
  
  <ol>
  <li>Raise request 1.</li>
  <li>Raise request 2.</li>
  <li>Raise request 3.</li>
  <li>Request 2 returns.</li>
  <li>Request 3 returns.</li>
  <li>Wait ~20 seconds.</li>
  <li>Request 1 returns.</li>
  </ol>
  
  <p>Instead, <strong>no</strong> requests return until request 1 is finished. </p>
  
  <p>I can confirm (based on the debug outputs), that the entry thread and sleepy thread id are different. I've intentionally used <code>TaskCreationOptions.LongRunning</code> to force the sleep onto a separate thread, but still the application refuses to service any new requests until that sleep has finished.</p>
  
  <p>Am I missing something fundamental about how async Web API controllers really work?</p>
  
  <hr>
  
  <pre><code>public class ValuesController : ApiController
  {
      private static bool _firstTime = true;
  
      public async Task&lt;string&gt; Get()
      {
          Debug.WriteLine("Entry thread id: {0}. Sync: {1}",
              Thread.CurrentThread.ManagedThreadId,
              SynchronizationContext.Current);
          await LongWaitAsync();
          return "FOOBAR";
      }
  
      private Task LongWaitAsync()
      {
          return Task.Factory.StartNew(() =&gt;
              {
                  if (_firstTime)
                  {
                      _firstTime = false;
                      Debug.WriteLine("Sleepy thread id: {0}. Sync: {1}",
                          Thread.CurrentThread.ManagedThreadId,
                          SynchronizationContext.Current);
                      Thread.Sleep(20000);
                      Debug.WriteLine("Finished sleeping");
                  }
              },
              CancellationToken.None,
              TaskCreationOptions.LongRunning,
              TaskScheduler.Default);
      }
  }
  </code></pre>