When blockingly waiting for the completion of an asynchronous operation -e.g., with Task.Wait()
,- it can block the execution of the enclosing synchronization context. This constellation can ultimately lead to the situation that the application becomes unresponsive.
var data = ReadAsync().Result;
Non-blockingly wait for the task completion using await
.
var data = await ReadAsync();
If it is impossible to make the caller method async
, first and foremost, search for the synchronous counterpart of the asynchronous method. If that is not possible, use a gate-keeper to avoid capturing the synchronization context: Enclose the call of the asynchronous method with Task.Run(...)
. This setup ensures that there is no synchronization context in the call-chain that may block the continuation of the synchronization context.
var data = Task.Run(async () => await ReadAsync()).Result;
var data = Task.Run(() => ReadAsync()).Result;
var data = Task.Run(ReadAsync).Result;
The gate-keeper is unnecessary when absolutely all await
usages in the chain make use of ConfigureAwait(false)
. However, if there is a single code-fragment missing this configuration, it can break the whole chain.