<p>La programmation asynchrone se “propage” à travers la base de code. Elle a été <a href="https://web.archive.org/web/20190126143814/https://blogs.msdn.microsoft.com/lucian/2011/04/15/async-ctp-refresh-design-changes/">comparée à un virus zombie</a>. La meilleure solution est de la laisser se propager, mais parfois ce n’est pas possible.</p>
<p>J’ai écrit quelques types dans ma bibliothèque <a href="https://github.com/StephenCleary/AsyncEx">Nito.AsyncEx</a> pour gérer une base de code partiellement asynchrone. Il n’existe aucune solution qui fonctionne dans toutes les situations, cependant.</p>
<p><strong>Solution A</strong></p>
<p>Si vous avez une méthode asynchrone simple qui n’a pas besoin de se synchroniser avec son contexte, vous pouvez utiliser <code>Task.WaitAndUnwrapException</code> :</p>
<pre><code class="lang-auto">var task = MyAsyncMethod();
var result = task.WaitAndUnwrapException();
</code></pre>
<p>Vous ne <em>voulez pas</em> utiliser <code>Task.Wait</code> ou <code>Task.Result</code> car ils encapsulent les exceptions dans une <code>AggregateException</code>.</p>
<p>Cette solution n’est appropriée que si <code>MyAsyncMethod</code> ne se synchronise pas avec son contexte. En d’autres termes, chaque <code>await</code> dans <code>MyAsyncMethod</code> devrait se terminer par <code>ConfigureAwait(false)</code>. Cela signifie qu’elle ne peut pas mettre à jour des éléments d’interface utilisateur ni accéder au contexte de requête <a href="http://ASP.NET">ASP.NET</a>.</p>
<p><strong>Solution B</strong></p>
<p>Si <code>MyAsyncMethod</code> a besoin de se synchroniser avec son contexte, vous pouvez peut-être utiliser <code>AsyncContext.RunTask</code> pour fournir un contexte imbriqué :</p>
<pre><code class="lang-auto">var result = AsyncContext.RunTask(MyAsyncMethod).Result;
</code></pre>
<p>*Mise à jour 14/04/2014 : Dans les versions plus récentes de la bibliothèque, l’API est la suivante :</p>
<pre><code class="lang-auto">var result = AsyncContext.Run(MyAsyncMethod);
</code></pre>
<p>(Il est correct d’utiliser <code>Task.Result</code> dans cet exemple car <code>RunTask</code> propagera les exceptions de <code>Task</code>).</p>
<p>La raison pour laquelle vous pourriez avoir besoin de <code>AsyncContext.RunTask</code> au lieu de <code>Task.WaitAndUnwrapException</code> est une possibilité de deadlock assez subtile qui se produit sur WinForms/WPF/SL/ASP.NET :</p>
<ul>
<li>
<p>Une méthode synchrone appelle une méthode asynchrone, obtenant une <code>Task</code>.</p>
</li>
<li>
<p>La méthode synchrone effectue une attente bloquante sur la <code>Task</code>.</p>
</li>
<li>
<p>La méthode <code>async</code> utilise <code>await</code> sans <code>ConfigureAwait</code>.</p>
</li>
<li>
<p>La <code>Task</code> ne peut pas se term</p>
</li>
</ul>
<p><em>(Réponse tronquée)</em></p>