title: How to use non-thread-safe async/await APIs and patterns with ASP.NET Web API?
body: <p>
  This question has been triggered by <a href="https://stackoverflow.com/q/20946677/1768303">EF Data Context - Async/Await &amp; Multithreading</a>. I've answered that one, but haven't provided any ultimate solution. </p>
  
  <p>The original problem is that there are a lot of useful .NET APIs out there (like Microsoft Entity Framework's  <a href="http://msdn.microsoft.com/en-us/library/system.data.entity.dbcontext%28v=vs.113%29.aspx" rel="noreferrer"><code>DbContext</code></a>), which provide asynchronous methods designed to be used with <code>await</code>, yet they are documented as <strong>not thread-safe</strong>. That makes them great for use in desktop UI apps, but not for server-side apps. <strong>[EDITED]</strong> <em>This might not actually apply to <code>DbContext</code>, here is Microsoft's <a href="https://entityframework.codeplex.com/wikipage?title=Task-based%20Asynchronous%20Pattern%20support%20in%20EF.#ThreadSafety" rel="noreferrer">statement on EF6 thread safety</a>, judge for yourself.</em> <strong>[/EDITED]</strong> </p>
  
  <p>There are also some established code patterns falling into the same category, like calling a WCF service proxy with <a href="http://msdn.microsoft.com/en-us/library/system.servicemodel.operationcontextscope%28v=vs.110%29.aspx" rel="noreferrer"><code>OperationContextScope</code></a> (asked <a href="https://stackoverflow.com/q/18284998/1768303">here</a> and <a href="https://stackoverflow.com/q/20877027/1768303">here</a>), e.g.:</p>
  
  <pre class="lang-cs prettyprint-override"><code>using (var docClient = CreateDocumentServiceClient())
  using (new OperationContextScope(docClient.InnerChannel))
  {
      return await docClient.GetDocumentAsync(docId);
  }
  </code></pre>
  
  <p>This may fail because <code>OperationContextScope</code> uses thread local storage in its implementation.</p>
  
  <p>The source of the problem is <code>AspNetSynchronizationContext</code> which is used in asynchronous ASP.NET pages to fulfill more HTTP requests with less threads from <code>ASP.NET</code> thread pool. With <code>AspNetSynchronizationContext</code>, an <code>await</code> continuation can be queued on a different thread from the one which initiated the async operation, while the original thread is released to the pool and can be used to serve another HTTP request. <strong>This substantially improves the server-side code scalability.</strong> The mechanism is described in great details in <a href="http://msdn.microsoft.com/en-us/magazine/gg598924.aspx" rel="noreferrer">It's All About the SynchronizationContext</a>, a must-read. So, while <strong>there is no concurrent API access</strong> involved, a potential thread switch still prevents us from using the aforementioned APIs.</p>
  
  <p><strong>I've been thinking about how to solve this without sacrificing the scalability.</strong> Apparently, the only way to have those APIs back is to <strong>maintain thread affinity</strong> for the scope of the async calls potentially affected by a thread switch. </p>
  
  <p>Let's say we have such thread affinity. Most of those calls are IO-bound anyway (<a href="http://blog.stephencleary.com/2013/11/there-is-no-thread.html" rel="noreferrer">There Is No Thread</a>). While an async task is pending, the thread it's been originated on can be used to serve a continuation of another similar task, which result is already available. Thus, it shouldn't hurt scalability too much. This approach is nothing new, in fact, <strong>a similar single-threaded model is <a href="http://nodejs.org/about/" rel="noreferrer">successfully used by Node.js</a></strong>. IMO, this is one of those things that make Node.js so popular.</p>
  
  <p>I don't see why this approach could not be used in ASP.NET context. A custom task scheduler (let's call it <code>ThreadAffinityTaskScheduler</code>) might maintain a separate pool of "affinity apartment" threads, to improve scalability even further. Once the task has been queued to one of those "apartment" threads, all <code>await</code> continuations inside the task will be taking place on the very same thread.</p>
  
  <p>Here's how a non-thread-safe API from <a href="https://stackoverflow.com/q/20946677/1768303">the linked question</a> might be used with such <code>ThreadAffinityTaskScheduler</code>: </p>
  
  <pre class="lang-cs prettyprint-override"><code>// create a global instance of ThreadAffinityTaskScheduler - per web app
  public static class GlobalState 
  {
      public static ThreadAffinityTaskScheduler TaScheduler { get; private set; }
  
      public static GlobalState 
      {
          GlobalState.TaScheduler = new ThreadAffinityTaskScheduler(
              numberOfThreads: 10);
      }
  }
  
  // ...
  
  // run a task which uses non-thread-safe APIs
  var result = await GlobalState.TaScheduler.Run(() =&gt; 
  {
      using (var dataContext = new DataContext())
      {
          var something = await dataContext.someEntities.FirstOrDefaultAsync(e =&gt; e.Id == 1);
          var morething = await dataContext.someEntities.FirstOrDefaultAsync(e =&gt; e.Id == 2);
          // ... 
          // transform "something" and "morething" into thread-safe objects and return the result
          return data;
      }
  }, CancellationToken.None);
  </code></pre>
  
  <p>I went ahead and <strong><a href="https://github.com/noserati/tpl/blob/master/ThreadAffinityTaskScheduler.cs" rel="noreferrer">implemented <code>ThreadAffinityTaskScheduler</code></a> as a proof of concept</strong>, based on the Stephen Toub's excellent <a href="http://blogs.msdn.com/b/pfxteam/archive/2010/04/07/9990421.aspx" rel="noreferrer"><code>StaTaskScheduler</code></a>. The pool threads maintained by <code>ThreadAffinityTaskScheduler</code> are not STA thread in the classic COM sense, but they do implement thread affinity for <code>await</code> continuations (<code>SingleThreadSynchronizationContext</code> is responsible for that).</p>
  
  <p>So far, I've tested this code as console app and it appears to work as designed. I haven't tested it inside an ASP.NET page yet. I don't have a lot of production ASP.NET development experience, so my questions are:</p>
  
  <ol>
  <li><p>Does it make sense to use this approach over simple <strong>synchronous</strong> invocation of non-thread-safe APIs in ASP.NET (the main goal is to avoid sacrificing scalability)?</p></li>
  <li><p>Is there alternative approaches, besides using synchronous API invocations or avoiding those APis at all?</p></li>
  <li><p>Has anyone used something similar in ASP.NET MVC or Web API projects and is ready to share his/her experience? </p></li>
  <li><p>Any advice on how to stress-test and profile this approach with ASP.NET would be
  appreciated.</p></li>
  </ol>