Appel de la méthode asynchrone de manière synchrone

J’ai une méthode async :

 public async Task GenerateCodeAsync() { ssortingng code = await GenerateCodeService.GenerateCodeAsync(); return code; } 

Je dois appeler cette méthode à partir d’une méthode synchrone.

Comment puis-je faire cela sans avoir à dupliquer la méthode GenerateCodeAsync pour que cela fonctionne de manière synchrone?

Mettre à jour

Pourtant, aucune solution raisonnable n’a été trouvée.

Cependant, je vois que HttpClient implémente déjà ce modèle

 using (HttpClient client = new HttpClient()) { // async HttpResponseMessage responseAsync = await client.GetAsync(url); // sync HttpResponseMessage responseSync = client.GetAsync(url).Result; } 

Vous pouvez accéder à la propriété Result de la tâche, ce qui entraînera le blocage de votre thread jusqu’à ce que le résultat soit disponible:

 ssortingng code = GenerateCodeAsync().Result; 

Remarque: Dans certains cas, cela peut entraîner un blocage: votre appel à Result bloque le thread principal, empêchant ainsi l’exécution du rest du code asynchrone. Vous disposez des options suivantes pour vous assurer que cela ne se produit pas:

  • Ajoutez .ConfigureAwait(false) à votre méthode de bibliothèque ou
  • exécutez explicitement votre méthode async dans un thread de pool de threads et attendez qu’elle se termine:

     ssortingng code = Task.Run(GenerateCodeAsync).Result; 

Vous devriez obtenir l’attendeur ( GetAwaiter() ) et terminer l’attente de l’achèvement de la tâche asynchrone ( GetResult() ).

 ssortingng code = GenerateCodeAsync().GetAwaiter().GetResult(); 

Vous devriez pouvoir faire cela en utilisant les delegates, l’expression lambda

 private void button2_Click(object sender, EventArgs e) { label1.Text = "waiting...."; Task sCode = Task.Run(async () => { ssortingng msg =await GenerateCodeAsync(); return msg; }); label1.Text += sCode.Result; } private Task GenerateCodeAsync() { return Task.Run(() => GenerateCode()); } private ssortingng GenerateCode() { Thread.Sleep(2000); return "I m back" ; } 

Je dois appeler cette méthode à partir d’une méthode synchrone.

C’est possible avec GenerateCodeAsync().Result ou GenerateCodeAsync().Wait() , comme le suggère l’autre réponse. Cela bloquerait le thread actuel jusqu’à ce que GenerateCodeAsync soit terminé.

Cependant, votre question est associée à asp.net , et vous avez également laissé le commentaire:

J’espérais une solution plus simple, en pensant que asp.net gérait beaucoup plus facilement que d’écrire autant de lignes de code

Mon point est, vous ne devriez pas bloquer sur une méthode asynchrone dans ASP.NET. Cela réduira l’évolutivité de votre application Web et risque de créer un blocage (lorsqu’une await en await intérieur de GenerateCodeAsync est publiée sur AspNetSynchronizationContext ). Utilisation de Task.Run(...).Result pour décharger quelque chose sur un thread de pool et le bloquer endommagera encore plus l’évolutivité, car il génère +1 thread supplémentaire pour traiter une requête HTTP donnée.

ASP.NET prend en charge les méthodes asynchrones, soit via des contrôleurs asynchrones (dans ASP.NET MVC et Web API), soit directement via AsyncManager et PageAsyncTask dans ASP.NET classique. Vous devriez l’utiliser. Pour plus de détails, cochez cette réponse .

Microsoft Identity a des méthodes d’extension qui appellent les méthodes asynchrones de manière synchrone. Par exemple, il y a la méthode GenerateUserIdentityAsync () et égal à CreateIdentity ()

Si vous regardez UserManagerExtensions.CreateIdentity (), il ressemble à ceci:

  public static ClaimsIdentity CreateIdentity(this UserManager manager, TUser user, ssortingng authenticationType) where TKey : IEquatable where TUser : class, IUser { if (manager == null) { throw new ArgumentNullException("manager"); } return AsyncHelper.RunSync(() => manager.CreateIdentityAsync(user, authenticationType)); } 

Voyons maintenant ce que fait AsyncHelper.RunSync

  public static TResult RunSync(Func> func) { var cultureUi = CultureInfo.CurrentUICulture; var culture = CultureInfo.CurrentCulture; return _myTaskFactory.StartNew(() => { Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = cultureUi; return func(); }).Unwrap().GetAwaiter().GetResult(); } 

Donc, ceci est votre wrapper pour la méthode asynchrone. Et s’il vous plaît ne lisez pas les données de Result – cela pourrait bloquer votre code en ASP.

Il y a un autre moyen – ce qui est suspect pour moi, mais vous pouvez le considérer aussi

  Result r = null; YourAsyncMethod() .ContinueWith(t => { r = t.Result; }) .Wait();