Microsoft a construit une classe AsyncHelper (interne) pour exécuter Async comme Sync. Le code source ressemble à:
internal static class AsyncHelper
{
private static readonly TaskFactory _myTaskFactory = new
TaskFactory(CancellationToken.None,
TaskCreationOptions.None,
TaskContinuationOptions.None,
TaskScheduler.Default);
public static TResult RunSync(Func> func)
{
return AsyncHelper._myTaskFactory
.StartNew>(func)
.Unwrap()
.GetAwaiter()
.GetResult();
}
public static void RunSync(Func func)
{
AsyncHelper._myTaskFactory
.StartNew(func)
.Unwrap()
.GetAwaiter()
.GetResult();
}
}
Les classes de base de Microsoft.AspNet.Identity ont uniquement des méthodes Async et pour les appeler comme Sync, il existe des classes avec des méthodes d'extension qui ressemblent à (exemple d'utilisation):
public static TUser FindById(this UserManager manager, TKey userId) where TUser : class, IUser where TKey : IEquatable
{
if (manager == null)
{
throw new ArgumentNullException("manager");
}
return AsyncHelper.RunSync(() => manager.FindByIdAsync(userId));
}
public static bool IsInRole(this UserManager manager, TKey userId, string role) where TUser : class, IUser where TKey : IEquatable
{
if (manager == null)
{
throw new ArgumentNullException("manager");
}
return AsyncHelper.RunSync(() => manager.IsInRoleAsync(userId, role));
}
Pour ceux qui se préoccupent des termes de licence du code, voici un lien vers un code très similaire (ajoute juste le support de la culture sur le thread) qui indique qu'il est sous licence MIT par Microsoft. https://github.com/aspnet/AspNetIdentity/blob/master/src/Microsoft.AspNet.Identity.Core/AsyncHelper.cs
Cela ne serait-il pas la même chose que d'appeler simplement Task.Run(async () => await AsyncFunc()).Result? À ma connaissance, Microsoft ne recommande désormais pas d'appeler TaskFactory.StartNew, car ils sont équivalents et l'un est plus lisible que l'autre.
Absolument pas.
La réponse simple est que
.Unwrap().GetAwaiter().GetResult() != .Result
Tout d'abord, le
Est-ce que Task.Result est la même chose que .GetAwaiter.GetResult()?
Deuxièmement, .Unwrap() fait en sorte que la configuration de la tâche ne bloque pas la tâche enveloppée.
Ce qui devrait inciter quiconque à se demander
Cela ne serait-il pas la même chose que d'appeler simplement Task.Run(async () => await AsyncFunc()).GetAwaiter().GetResult()
Ce qui serait alors un Cela dépend.
En ce qui concerne l'utilisation de Task.Start(), Task.Run() et Task.Factory.StartNew()
Extrait:
Task.Run utilise TaskCreationOptions.DenyChildAttach ce qui signifie que les tâches enfant ne peuvent pas être attachées au parent et il utilise TaskScheduler.Default ce qui signifie que celui qui exécute les tâches sur le pool de threads sera toujours utilisé pour exécuter les tâches.
Task.Factory.StartNew utilise TaskScheduler.Current ce qui signifie le planificateur du thread actuel, il pourrait être TaskScheduler.Default mais pas toujours.
Lecture supplémentaire:
Spécification d'un contexte de synchronisation
Contexte de synchronisation ASP.NET Core
Pour plus de sécurité, ne serait-il pas mieux de l'appeler ainsi AsyncHelper.RunSync(async () => await AsyncMethod().ConfigureAwait(false));
De cette manière, nous disons à la méthode "interne" "s'il vous plaît ne pas essayer de synchroniser avec le contexte supérieur et débloquer"
Point vraiment important de alex-from-jitbit et comme la plupart des questions architecturales d'objets cela dépend.
En tant que méthode d'extension, voulez-vous imposer cela pour absolument chaque appel, ou laissez-vous le programmeur utiliser la fonction configurer cela sur ses propres appels Async? Je pourrais voir un cas d'utilisation pour appeler trois scénarios; cela a probablement plus de sens dans la plupart des cas, mais compte tenu qu'il n'y a pas de Contexte dans ASP.Net Core si vous pouviez garantir que c'était par exemple interne pour un ASP.Net Core, alors cela n'aurait pas d'importance.
4 votes
Je suis également tombé sur ce problème. En remplaçant un RoleProvider, vous ne pouvez pas modifier la signature de la méthode GetRolesForUser pour la rendre asynchrone. Vous ne pouvez donc pas utiliser await pour appeler de manière asynchrone une API. Ma solution temporaire a été d'ajouter des méthodes synchrones à ma classe HttpClient générique, mais j'aimerais savoir si cela est possible (et quelles pourraient en être les implications).
3 votes
Parce que votre méthode
async void Foo()
ne renvoie pas deTask
, cela signifie qu'un appelant ne peut pas savoir quand elle se termine, elle doit plutôt renvoyerTask
.1 votes
En créant un lien vers une question / réponse associée sur la façon de le faire sur un thread UI.
2 votes
J'ai utilisé cette méthode et semble faire le travail : MyMethodAsync.GetAwaiter().GetResult(); Avant cela, vous voudriez peut-être consulter l'article suivant qui se résume finalement à des interblocages et à une pénurie de threadpool : medium.com/rubrikkgroup/…
0 votes
@Timothy Lee Russell, je ne pense pas que GetRolesForUser() devrait faire beaucoup. Surtout pas appeler des méthodes asynchrones prenant du temps.
0 votes
@Dai J'ai édité la question et corrigé cette erreur (probablement non intentionnelle).