title: ConfigureAwait(false) vs setting sync context to null
body: <p>I often see recommended for async library code, that we should use <code>ConfigureAwait(false)</code> on all async calls to avoid situations where the return of our call will be scheduled on a UI thread or a web request synchronization context  causing issues with deadlocks among other things.</p>
  
  <p>One of the problems with using <code>ConfigureAwait(false)</code> is that it isn't something you can just do on the entry point of your library call. In order for it to be effective it must be done all the way down the stack throughout your library code.</p>
  
  <p>It seems to me that a viable alternative is to simply set the current synchronization context to null at the top-level public-facing entry points of the library, and just forget about <code>ConfigureAwait(false)</code>. However, I don't see many instances of people taking or recommending this approach.</p>
  
  <p>Is there anything wrong with simply setting the current synchronization context to null on the library entry points? Are there any potential problems with this approach (other than the possible insignificant performance hit of having the await post to the default synchronization context)? </p>
  
  <p>(EDIT #1) Adding some example code of what I mean:</p>
  
  <pre><code>   public class Program
      {
          public static void Main(string[] args)
          {
              SynchronizationContext.SetSynchronizationContext(new LoggingSynchronizationContext(1));
  
              Console.WriteLine("Executing library code that internally clears synchronization context");
              //First try with clearing the context INSIDE the lib
              RunTest(true).Wait();
              //Here we again have the context intact
              Console.WriteLine($"After First Call Context in Main Method is {SynchronizationContext.Current?.ToString()}");
  
  
              Console.WriteLine("\nExecuting library code that does NOT internally clear the synchronization context");
              RunTest(false).Wait();
              //Here we again have the context intact
              Console.WriteLine($"After Second Call Context in Main Method is {SynchronizationContext.Current?.ToString()}");
  
          }
  
          public async static Task RunTest(bool clearContext)
          {
              Console.WriteLine($"Before Lib call our context is {SynchronizationContext.Current?.ToString()}");
              await DoSomeLibraryCode(clearContext);
              //The rest of this method will get posted to my LoggingSynchronizationContext
  
              //But.......
              if(SynchronizationContext.Current == null){
                  //Note this will always be null regardless of whether we cleared it or not
                  Console.WriteLine("We don't have a current context set after return from async/await");
              }
          }
  
  
          public static async Task DoSomeLibraryCode(bool shouldClearContext)
          {
              if(shouldClearContext){
                  SynchronizationContext.SetSynchronizationContext(null);
              }
              await DelayABit();
              //The rest of this method will be invoked on the default (null) synchronization context if we elected to clear the context
              //Or it should post to the original context otherwise
              Console.WriteLine("Finishing library call");
          }
  
          public static Task DelayABit()
          {
              return Task.Delay(1000);
          }
  
      }
  
      public class LoggingSynchronizationContext : SynchronizationContext
      {
  
          readonly int contextId;
          public LoggingSynchronizationContext(int contextId)
          {
              this.contextId = contextId;
          }
          public override void Post(SendOrPostCallback d, object state)
          {
              Console.WriteLine($"POST TO Synchronization Context (ID:{contextId})");
              base.Post(d, state);
          }
  
          public override void Send(SendOrPostCallback d, object state)
          {
              Console.WriteLine($"Post Synchronization Context (ID:{contextId})");
              base.Send(d, state);
          }
  
          public override string ToString()
          {
              return $"Context (ID:{contextId})";
          }
      }
  </code></pre>
  
  <p>The execution of this will output:</p>
  
  <pre><code>Executing library code that internally clears synchronization context
  Before Lib call our context is Context (ID:1) 
  Finishing library call 
  POST TO Synchronization Context (ID:1)
  We don't have a current context set after return from async/await
  After First Call Context in Main Method is Context (ID:1)
  
  Executing library code that does NOT internally clear the synchronization context 
  Before Lib call our context is Context (ID:1) POST TO Synchronization Context (ID:1) 
  Finishing library call
  POST TO Synchronization Context (ID:1) 
  We don't have a current context set after return from async/await
  After Second Call Context in Main Method is Context (ID:1)
  </code></pre>
  
  <p>This all works like I would expect, but I don't come across people recommending libraries do this internally. I find that requiring every internal await point be called with <code>ConfigureAwait(false)</code> is annoying, and even one missed <code>ConfigureAwait()</code> can cause trouble throughout an application. This seems like it would solve the issue simply at the public entry-point of the library with a single line of code. What am I missing?</p>
  
  <p>(EDIT #2)</p>
  
  <p>Based on some feedback from Alexei's answer,  it seems I hadn't consider the possibility of a task not being immediately awaited. Since the execution context is captured at the time of the await (not the time of the async call), that would mean the change to <code>SynchronizationContext.Current</code> would not be isolated to the library method. Based on this it would seem that it should suffice to force a capture of the context by wrapping the internal logic of the library in a call that forces an wait. For example:</p>
  
  <pre><code>    async void button1_Click(object sender, EventArgs e)
      {
          var getStringTask = GetStringFromMyLibAsync();
          this.textBox1.Text = await getStringTask;
      }
  
      async Task&lt;string&gt; GetStringFromMyLibInternal()
      {
          SynchronizationContext.SetSynchronizationContext(null);
          await Task.Delay(1000);
          return "HELLO WORLD";
      }
  
      async Task&lt;string&gt; GetStringFromMyLibAsync()
      {
          //This forces a capture of the current execution context (before synchronization context is nulled
          //This means the caller's context should be intact upon return
          //even if not immediately awaited.
          return await GetStringFromMyLibInternal();          
      }
  </code></pre>
  
  <p>(EDIT #3)</p>
  
  <p>Based on the discussion on Stephen Cleary's answer. There are some problems with this approach. But we can do a similar approach by wrapping the library call in a non-async method that still returns a task, but takes care of resetting the syncrhonization context at the end. (Note this uses the SynchronizationContextSwitcher from Stephen's AsyncEx library.</p>
  
  <pre><code>    async void button1_Click(object sender, EventArgs e)
      {
          var getStringTask = GetStringFromMyLibAsync();
          this.textBox1.Text = await getStringTask;
      }
  
      async Task&lt;string&gt; GetStringFromMyLibInternal()
      {
          SynchronizationContext.SetSynchronizationContext(null);
          await Task.Delay(1000);
          return "HELLO WORLD";
      }
  
      Task&lt;string&gt; GetStringFromMyLibAsync()
      {
          using (SynchronizationContextSwitcher.NoContext())
          {
              return GetStringFromMyLibInternal();          
          } 
          //Context will be restored by the time this method returns its task.
      }
  </code></pre>