attendre des travaux mais appelant task.Result se bloque / deadlocks

J’ai les quatre tests suivants et le dernier se bloque quand je le lance, ma question est la suivante:

[Test] public void CheckOnceResultTest() { Assert.IsTrue(CheckStatus().Result); } [Test] public async void CheckOnceAwaitTest() { Assert.IsTrue(await CheckStatus()); } [Test] public async void CheckStatusTwiceAwaitTest() { Assert.IsTrue(await CheckStatus()); Assert.IsTrue(await CheckStatus()); } [Test] public async void CheckStatusTwiceResultTest() { Assert.IsTrue(CheckStatus().Result); // This hangs Assert.IsTrue(await CheckStatus()); } private async Task CheckStatus() { var restClient = new RestClient(@"https://api.test.nordnet.se/next/1"); Task<IRestResponse> restResponse = restClient.ExecuteTaskAsync(new RestRequest(Method.GET)); IRestResponse response = await restResponse; return response.Data.SystemRunning; } 

J’utilise cette méthode d’extension pour restsharp RestClient :

 public static class RestClientExt { public static Task<IRestResponse> ExecuteTaskAsync(this RestClient client, IRestRequest request) where T : new() { var tcs = new TaskCompletionSource<IRestResponse>(); RestRequestAsyncHandle asyncHandle = client.ExecuteAsync(request, tcs.SetResult); return tcs.Task; } } 
 public class DummyServiceStatus { public ssortingng Message { get; set; } public bool ValidVersion { get; set; } public bool SystemRunning { get; set; } public bool SkipPhrase { get; set; } public long Timestamp { get; set; } } 

Pourquoi le dernier test est-il suspendu?

Vous vous trouvez dans la situation de blocage standard que je décris sur mon blog et dans un article MSDN : la méthode async tente de planifier sa poursuite sur un thread bloqué par l’appel à Result .

Dans ce cas, votre SynchronizationContext est celui utilisé par NUnit pour exécuter des méthodes de test async void . J’essaierais plutôt d’utiliser les méthodes de test de async Task .

Acquérir une valeur via une méthode asynchrone:

 var result = Task.Run(() => asyncGetValue()).Result; 

Appel synchrone d’une méthode asynchrone

 Task.Run( () => asyncMethod()).Wait(); 

Aucun problème de blocage ne se produira en raison de l’utilisation de Task.Run.

Vous pouvez éviter le blocage en ajoutant ConfigureAwait(false) à cette ligne:

 IRestResponse response = await restResponse; 

=>

 IRestResponse response = await restResponse.ConfigureAwait(false); 

J’ai décrit cet écueil sur mon blog Les pièges de l’async / wait

Vous bloquez l’interface utilisateur à l’aide de la propriété Task.Result. Dans la documentation MSDN, ils ont clairement mentionné que,

“La propriété Result est une propriété de blocage. Si vous essayez d’y accéder avant que sa tâche ne soit terminée, le thread actuellement actif est bloqué jusqu’à ce que la tâche se termine et que la valeur soit disponible. Dans la plupart des cas, vous devez accéder à la valeur ou attendre au lieu d’accéder directement à la propriété. ”

La meilleure solution pour ce scénario serait de supprimer les méthodes wait & async des méthodes et d’utiliser uniquement la tâche sur laquelle vous retournez le résultat. Cela ne gâchera pas votre séquence d’exécution.

Si vous ne recevez aucun rappel ou contrôle, raccroche, après avoir appelé la fonction Async Service / API. Vous devez configurer le contexte pour renvoyer le résultat sur le même contexte appelé. Utilisez TestAsync (). ConfigureAwait (continueOnCapturedContext: false);

Vous serez confronté à ce problème uniquement dans les applications Web, mais pas dans le dossier principal statique statique.