Вызов синхронного асинхронного метода
У меня есть метод async
:
public async Task GenerateCodeAsync() { string code = await GenerateCodeService.GenerateCodeAsync(); return code; }
Мне нужно вызвать этот метод синхронным методом.
Как я могу это сделать без дублирования метода GenerateCodeAsync
чтобы это работало синхронно?
- Запуск нескольких задач async и ожидание их завершения
- Выполнение задач параллельно
- Когда использовать Task.Delay, когда использовать Thread.Sleep?
- WaitAll vs WhenAll
- Шаблон для самоотдачи и перезапуска задачи
Обновить
Однако разумного решения не найдено.
Однако я вижу, что HttpClient
уже реализует этот шаблон
using (HttpClient client = new HttpClient()) { // async HttpResponseMessage responseAsync = await client.GetAsync(url); // sync HttpResponseMessage responseSync = client.GetAsync(url).Result; }
- Очередь процесса с многопоточным или задачами
- В чем разница между возвратом пустоты и возвратом задачи?
- Разница между TPL и async / await (Обработка streamов)
- Каков правильный способ отмены асинхронной операции, которая не принимает CancellationToken?
- ConfigureAwait подталкивает продолжение в stream пула
- Использовать Task.Run () в синхронном методе, чтобы избежать тупиковой остановки в асинхронном методе?
- Выполнение задачи в фоновом режиме в приложении WPF
- Почему это асинхронное действие зависает?
Вы можете получить доступ к свойству Result
задачи, что приведет к блокировке streamа до получения результата:
string code = GenerateCodeAsync().Result;
Примечание. В некоторых случаях это может привести к тупику: ваш вызов функции « Result
блокирует основной stream, тем самым предотвращая выполнение оставшейся части асинхронного кода. У вас есть следующие опции, чтобы убедиться, что этого не происходит:
- Добавьте
.ConfigureAwait(false)
в свой библиотечный метод или -
явно выполните ваш метод async в streamе пула streamов и дождитесь его завершения:
string code = Task.Run(GenerateCodeAsync).Result;
Вы должны получить awaiter ( GetAwaiter()
) и закончить ожидание завершения асинхронной задачи ( GetResult()
).
string code = GenerateCodeAsync().GetAwaiter().GetResult();
Вы должны это сделать, используя delegates, выражение lambda
private void button2_Click(object sender, EventArgs e) { label1.Text = "waiting...."; Task sCode = Task.Run(async () => { string msg =await GenerateCodeAsync(); return msg; }); label1.Text += sCode.Result; } private Task GenerateCodeAsync() { return Task.Run (() => GenerateCode()); } private string GenerateCode() { Thread.Sleep(2000); return "I m back" ; }
Мне нужно вызвать этот метод синхронно.
Это можно сделать с помощью GenerateCodeAsync().Result
или GenerateCodeAsync().Wait()
, как предлагает другой ответ. Это блокирует текущий stream до завершения GenerateCodeAsync
.
Однако ваш вопрос помечен asp.net , и вы также оставили комментарий:
Я надеялся на более простое решение, считая, что asp.net обрабатывает это намного проще, чем писать так много строк кода
Я хочу сказать , что вы не должны блокировать asynchronous метод в ASP.NET. Это уменьшит масштабируемость вашего веб-приложения и может создать тупик (когда AspNetSynchronizationContext
продолжения внутри GenerateCodeAsync
отправляется в AspNetSynchronizationContext
). Использование Task.Run(...).Result
для того, чтобы выгрузить что-то в stream пула, а затем заблокировать, еще больше повредит масштабируемость, поскольку он обрабатывает +1 больше streamа для обработки заданного HTTP-запроса.
ASP.NET имеет встроенную поддержку асинхронных методов либо через асинхронные controllerы (в ASP.NET MVC и Web API), либо напрямую через AsyncManager
и PageAsyncTask
в classическом ASP.NET. Вы должны использовать его. Для получения дополнительной информации проверьте этот ответ .
У Microsoft Identity есть методы расширения, которые синхронно вызывают методы асинхронного доступа. Например, существует метод GenerateUserIdentityAsync () и равный CreateIdentity ()
Если вы посмотрите UserManagerExtensions.CreateIdentity (), это выглядит так:
public static ClaimsIdentity CreateIdentity(this UserManager manager, TUser user, string authenticationType) where TKey : IEquatable where TUser : class, IUser { if (manager == null) { throw new ArgumentNullException("manager"); } return AsyncHelper.RunSync(() => manager.CreateIdentityAsync(user, authenticationType)); }
Теперь давайте посмотрим, что делает 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(); }
Итак, это ваш обертку для асинхронного метода. И, пожалуйста, не читайте данные из Result – это потенциально блокирует ваш код в ASP.
Есть еще один способ – это подозрительно для меня, но вы тоже можете его рассмотреть
Result r = null; YourAsyncMethod() .ContinueWith(t => { r = t.Result; }) .Wait();