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:
.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();