Implementing a reusable adaptor type of library on top of Azure Document Db Client SDK.
The library can run anywhere, not only in an ASP.NET Core web service, but i
The continuations unlike a synchronous code which precedes an await
call, are executed in context of different call-stack calls. In particular they are scheduled for execution as separate delegates and there is no call-stack relationship between them. So specifying ConfigureAwait(false)
for very last continuation execution will take effect only for this specific continuation, other continuations will still execute using their individual scheduling configuration. That is, if your goal is to ensure not capturing a synchronization context by any continuation in your library (in order to prevent potential dead locks or any other reason) then you should configure all await
calls which have continuations with ConfigureAwait(false)
.
ConfigureAwait(false)
is used to prevent execution on initial SynchronizationContext
. If you're working on library which doesn't need access to UI thread for instance (in case of WPF or WinForms) you should use ConfigureAwait(false)
on all levels. Otherwise SynchronizationContext
will be restored. Here is an example of simple WinForms application:
public partial class Form1 : Form
{
static readonly HttpClient _hcli = new HttpClient();
public Form1()
{
InitializeComponent();
}
private static string log;
private async void button1_Click(object sender, EventArgs e)
{
log = "";
await M3();
MessageBox.Show(log);
}
static async Task<string> M3()
{
LogBefore(nameof(M3));
var str = await M2();
LogAfter(nameof(M3));
return str;
}
static async Task<string> M2()
{
LogBefore(nameof(M2));
var str = await M1();
LogAfter(nameof(M2));
return str;
}
static async Task<string> M1()
{
LogBefore(nameof(M1));
var str = await _hcli.GetStringAsync("http://mtkachenko.me").ConfigureAwait(false);
LogAfter(nameof(M1));
return str;
}
static void LogBefore(string method)
{
log += $"before {method} {Thread.CurrentThread.ManagedThreadId} {SynchronizationContext.Current == null}, ";
}
static void LogAfter(string method)
{
log += $"after {method} {Thread.CurrentThread.ManagedThreadId} {SynchronizationContext.Current == null}, ";
}
}
Output:
before M3 1 False
before M2 1 False
before M1 1 False
after M1 12 True //sync.context skipped because of .ConfigureAwait(false)
after M2 1 False //sync.context restored
after M3 1 False //sync.context restored