title: Using ASP.NET Web API, my ExecutionContext isn't flowing in async actions
body: <h2>I'm having difficulty understanding the mechanics behind ExecutionContext.</h2>
  
  <p>From what I've read online, context-sensitive items such as security (Thread Principal), culture, etc, should flow across asynchronous threads within the bounds of an execution unit of work.</p>
  
  <p>I'm encountering very confusing and potentially dangerous bugs though. I'm noticing my thread's CurrentPrincipal is getting lost across async execution.</p>
  
  <hr>
  
  <p>Here is an example ASP.NET Web API scenario:</p>
  
  <p>First, let's setup a simple Web API configuration with two delegating handlers for testing purposes. </p>
  
  <p>All they do is write out debug information and pass the request/response on through, except the first "DummyHandler" which sets the thread's principal as well as a piece of data to be shared across the context (the request's correlation ID).</p>
  
  <pre><code>public static class WebApiConfig
  {
      public static void Register(HttpConfiguration config)
      {
          config.MessageHandlers.Add(new DummyHandler());
          config.MessageHandlers.Add(new AnotherDummyHandler());
  
          config.Routes.MapHttpRoute(
              name: "DefaultApi",
              routeTemplate: "api/{controller}/{id}",
              defaults: new { id = RouteParameter.Optional }
          );
      }
  }
  
  public class DummyHandler : DelegatingHandler
  {
      protected override Task&lt;HttpResponseMessage&gt; SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
      {
          CallContext.LogicalSetData("rcid", request.GetCorrelationId());
          Thread.CurrentPrincipal = new ClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new[]{ new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "dgdev") }, "myauthisthebest")));
  
          Debug.WriteLine("Dummy Handler Thread: {0}", Thread.CurrentThread.ManagedThreadId);
          Debug.WriteLine("User: {0}", (Object)Thread.CurrentPrincipal.Identity.Name);
          Debug.WriteLine("RCID: {0}", CallContext.LogicalGetData("rcid"));
  
          return base.SendAsync(request, cancellationToken)
                     .ContinueWith(task =&gt;
                         {
                             Debug.WriteLine("Dummy Handler Thread: {0}", Thread.CurrentThread.ManagedThreadId);
                             Debug.WriteLine("User: {0}", (Object)Thread.CurrentPrincipal.Identity.Name);
                             Debug.WriteLine("RCID: {0}", CallContext.LogicalGetData("rcid"));
  
                             return task.Result;
                         });
      }
  }
  
  public class AnotherDummyHandler : MessageProcessingHandler
  {
      protected override HttpRequestMessage ProcessRequest(HttpRequestMessage request, CancellationToken cancellationToken)
      {
          Debug.WriteLine("  Another Dummy Handler Thread: {0}", Thread.CurrentThread.ManagedThreadId);
          Debug.WriteLine("  User: {0}", (Object)Thread.CurrentPrincipal.Identity.Name);
          Debug.WriteLine("  RCID: {0}", CallContext.LogicalGetData("rcid"));
  
          return request;
      }
  
      protected override HttpResponseMessage ProcessResponse(HttpResponseMessage response, CancellationToken cancellationToken)
      {
          Debug.WriteLine("  Another Dummy Handler Thread: {0}", Thread.CurrentThread.ManagedThreadId);
          Debug.WriteLine("  User: {0}", (Object)Thread.CurrentPrincipal.Identity.Name);
          Debug.WriteLine("  RCID: {0}", CallContext.LogicalGetData("rcid"));
  
          return response;
      }
  }
  </code></pre>
  
  <hr>
  
  <p>Simple enough. Next let's add a single ApiController to handle an HTTP POST, as if you were uploading files.</p>
  
  <pre><code>public class UploadController : ApiController
  {
      public async Task&lt;HttpResponseMessage&gt; PostFile()
      {
          Debug.WriteLine("    Thread: {0}", Thread.CurrentThread.ManagedThreadId);
          Debug.WriteLine("    User: {0}", (Object)Thread.CurrentPrincipal.Identity.Name);
          Debug.WriteLine("    RCID: {0}", CallContext.LogicalGetData("rcid"));
  
          if (!Request.Content.IsMimeMultipartContent())
          {
              throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
          }
  
          try
          {
              await Request.Content.ReadAsMultipartAsync(
                  new MultipartFormDataStreamProvider(
                      HttpRuntime.AppDomainAppPath + @"upload\temp"));
  
              Debug.WriteLine("    Thread: {0}", Thread.CurrentThread.ManagedThreadId);
              Debug.WriteLine("    User: {0}", (Object)Thread.CurrentPrincipal.Identity.Name);
              Debug.WriteLine("    RCID: {0}", CallContext.LogicalGetData("rcid"));
  
              return new HttpResponseMessage(HttpStatusCode.Created);
          }
          catch (Exception e)
          {
              return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
          }
      }
  }
  </code></pre>
  
  <hr>
  
  <p>Upon running a test with Fiddler, this is the output I receive:</p>
  
  <pre><code>Dummy Handler Thread: 63
  User: dgdev
  RCID: 6d542847-4ceb-4511-85e5-d1b5bf3be476
  
    Another Dummy Handler Thread: 63
    User: dgdev
    RCID: 6d542847-4ceb-4511-85e5-d1b5bf3be476
  
      Thread: 63
      User: dgdev
      RCID: 6d542847-4ceb-4511-85e5-d1b5bf3be476
  
      Thread: 77
      User:                                     &lt;&lt;&lt;  PRINCIPAL IS LOST AFTER ASYNC
      RCID: 6d542847-4ceb-4511-85e5-d1b5bf3be476
  
    Another Dummy Handler Thread: 63
    User:                                       &lt;&lt;&lt;  PRINCIPAL IS STILL LOST
    RCID: 6d542847-4ceb-4511-85e5-d1b5bf3be476
  
  Dummy Handler Thread: 65
  User: dgdev                                   &lt;&lt;&lt;  PRINCIPAL IS BACK?!?
  RCID: 6d542847-4ceb-4511-85e5-d1b5bf3be476
  </code></pre>
  
  <hr>
  
  <p>To make matters more confusing, When I append the follow to the async line:</p>
  
  <pre><code>await Request.Content.ReadAsMultipartAsync(
      new MultipartFormDataStreamProvider(..same as before..))
  .ConfigureAwait(false); &lt;&lt;&lt;&lt;&lt;&lt;
  </code></pre>
  
  <p>I now receive this output:</p>
  
  <pre><code>Dummy Handler Thread: 40
  User: dgdev
  RCID: 8d944500-cb52-4362-8537-dab405fa12a2
  
    Another Dummy Handler Thread: 40
    User: dgdev
    RCID: 8d944500-cb52-4362-8537-dab405fa12a2
  
      Thread: 40
      User: dgdev
      RCID: 8d944500-cb52-4362-8537-dab405fa12a2
  
      Thread: 65
      User: dgdev                               &lt;&lt;&lt;  PRINCIPAL IS HERE!
      RCID: 8d944500-cb52-4362-8537-dab405fa12a2
  
    Another Dummy Handler Thread: 65
    User:                                       &lt;&lt;&lt;  PRINCIPAL IS LOST
    RCID: 8d944500-cb52-4362-8537-dab405fa12a2
  
  Dummy Handler Thread: 40
  User: dgdev
  RCID: 8d944500-cb52-4362-8537-dab405fa12a2
  </code></pre>
  
  <p>The point here is this. The code following the async my in fact call my business logic or simply require the security context be properly set. There is a potential integrity problem going on.</p>
  
  <p>Can anyone help shed some light one what is happening?</p>
  
  <p>Thanks in advance.</p>