ASP.NET MVC 4 асинхронное дочернее действие
У меня есть приложение ASP.NET MVC 4, ориентированное на .NET 4.5. Одно из наших дочерних действий вызывает вызов веб-службы с использованием HttpClient.
Поскольку мы блокируем IO, ожидая ответа HttpClient, имеет смысл преобразовать код в шаблон async/await. Однако, когда MVC 4 пытается выполнить дочернее действие, мы получаем следующее сообщение об ошибке:
HttpServerUtility.Execute заблокирован, ожидая завершения асинхронной операции.
На первый взгляд кажется, что MVC 4 не поддерживает async/wait в дочернем действии. Единственная оставшаяся опция - запустить с использованием синхронного кода и принудительно выполнить "Ожидание" в задаче async.
Как мы все знаем, касание .Result или .Wait() в async-задании в контексте ASP.NET вызовет немедленный тупик. Моя асинхронная логика завернута в библиотеку классов, поэтому я не могу использовать трюк "wait at blah.ConfigureAwait(false)". Помните, что тегирование "async" на дочернем действии и использование await вызывает ошибку, и это мешает мне настроить ожидание.
В этот момент я нарисован в углу. Есть ли способ использовать асинхронные методы в дочернем действии MVC 4? Кажется, что плоская ошибка без обходных решений.
Ответы
Ответ 1
Есть еще части MVC, которые не являются async
-другими; Надеюсь, они будут рассмотрены в будущем. Пожалуйста, создайте для этого проблему Connect или UserVoice.
Моя асинхронная логика завернута в библиотеку классов, поэтому я не могу использовать трюк "wait at blah.ConfigureAwait(false)".
Вероятно, вы должны добавить ConfigureAwait(false)
к вызовам в вашей библиотеке классов (если можете).
Вы также можете взломать альтернативное решение. Если для вашего метода библиотеки классов не нужен контекст ASP.NET, тогда у вас может быть поток потока нитей (a), ожидающий вас:
try
{
var result = Task.Run(async () => { await MyHttpRequest(...); }).Result;
}
catch (AggregateException ex) { ... }
Эффект похож на ConfigureAwait(false)
: поскольку MyHttpRequest
работает в контексте пула потоков, он не будет пытаться войти в контекст ASP.NET, когда он будет завершен.
Ответ 2
Формат ответа Стивена не совсем сработал у меня (возможно, это проблема асинхронного Noob, но эй).
Мне пришлось написать выражение async в этом формате, чтобы получить строго типизированное возвращаемое значение.
Person myPerson = Task.Run(() => asyncMethodWhichGetsPerson(id)).Result;