Stephen's article explains that the SynchronizationContext does not "flow" as the ExecutionContext does (although the SynchronizationContext is part of the ExecutionContext ).
ExecutionContext always flowing. Even if you use Task.Run , therefore, if the SynchronizationContext will flow with it, Task.Run will be executed in the user interface thread, and therefore Task.Run will be pointless. SynchronizationContext does not flow, it is more likely to be fixed when an asynchronous point is reached (i.e. await ), and continued after its publication (unless explicitly stated otherwise).
The difference is explained in this quote:
Now we have a very important point: flowing ExecutionContext semantically very different from capturing and placing on a SynchronizationContext .
With an ExecutionContext thread, you grab state from a single thread, and then restore that state to its environment during the execution of delegated delegates. This is not what happens when capturing and using a SynchronizationContext . The capture part is the same as you capture data from the current stream, but then use this state in different ways. Instead of making this state current during a delegate call, SynchronizationContext.Post you simply use this captured state to call a delegate. Where and when and how this delegate is executed depends entirely on the implementation of the Post method.
In your case, this means that when you PerformServiceCall 1 Current SynchronizationContext really WindowsFormsSynchronizationContext because you have not reached any asynchronous point yet and are still in the user interface thread (remember that the part before the first await in the async method will be executed synchronously in the calling thread, therefore LogSyncContext("PerformServiceCall 1"); will happen before ConfigureAwait(false) in the task returned from PerformServiceCall ).
You only "go" with the UI SynchronizationContext when you use ConfigureAwait(false) (which does not take into account the captured SynchronizationContext ). This happens for the first time on HttpClient.GetAsync , and then again on PerformServiceCall .
source share