Вызов ConfigureAwait из действия ASP.NET MVC
Я работал над презентацией и думал, что следующее должно потерпеть неудачу, поскольку ActionResult не возвращается в правильном контексте. Я загрузил его с помощью VS и не получил никаких ошибок. Я отлаживал его и знал, что он переключает потоки. Поэтому кажется, что это законный код.
Не заботится ли ASP.NET о том, какой контекст или поток он включен, как клиентское приложение? Если да, то какая цель предоставляет AspNetSynchronizationContext? Я не чувствую себя правильно, добавляя ConfigureAwait в самом действии. Что-то кажется неправильным. Может кто-нибудь объяснить?
public async Task<ActionResult> AsyncWithBackendTest()
{
var result = await BackendCall().ConfigureAwait(false);
var server = HttpContext.Server;
HttpContext.Cache["hello"] = "world";
return Content(result);
}
Ответы
Ответ 1
ASP.NET не имеет потребности в "пользовательском интерфейсе", которую выполняют многие приложения для клиентов (из-за структуры пользовательского интерфейса ниже). Этот контекст не связан с привязкой к потоку, но для отслеживания прогресса страницы (и других вещей, таких как перенос контекста безопасности для запроса).
Стивен Туб упоминает об этом в статье MSDN:
Windows Forms - это не единственная среда, которая обеспечивает SynchronizationContext-производный класс. ASP.NET также предоставляет один, AspNetSynchronizationContext, хотя он не является общедоступным и не предназначен для внешнего потребления. Скорее, он используется под обложками ASP.NET для облегчения работы асинхронных страниц в ASP.NET 2.0 (дополнительную информацию см. В разделе msdn.microsoft.com/msdnmag/issues/05/10/WickedCode). Эта реализация позволяет ASP.NET предотвращать завершение обработки страницы пока все выдающиеся асинхронные вызовы не будут завершены.
Более подробная информация о контексте синхронизации приведена в статье Стивена Клири из прошлого года.
На рисунке 4, в частности, показано, что у него нет "специфического потока" поведения WinForms/WPF, но все это замечательно.
Если сразу несколько операций выполняются для одного и того же приложения, AspNetSynchronizationContext гарантирует, что они время. Они могут выполняться в любом потоке, но этот поток будет иметь идентичность и культура исходной страницы.
Ответ 2
В вашем коде HttpContext
является членом вашего базового класса AsyncController
. Это не текущий контекст для исполняемого потока.
Кроме того, в вашем случае HttpContext
остается в силе, так как запрос еще не завершен.
Я не могу проверить это на данный момент, но я ожидаю, что это сработает, если вы использовали System.Web.HttpContext.Current
вместо HttpContext
.
P.S. Безопасность всегда распространяется независимо от ConfigureAwait
- это имеет смысл, если вы думаете об этом. Я не уверен в культуре, но я не удивлюсь, если бы она всегда распространялась.
Ответ 3
Это происходит потому, что контроллер захватывает контекст, а использование System.Web.HttpContext
- это прямой доступ к тому, что является частью контекста синхронизации.
Если мы посмотрим на источники ASP.NET MVC5, то увидим, что класс ControllerBase
, от которого наследуются все контроллеры, имеет свой собственный ControllerContext
который построен из RequestContext
.
Я бы предположил, что это означает, что в то время как контекст синхронизации теряется после ConfigureAwait(false);
Состояние Controller
в котором происходит продолжение, все еще имеет доступ к состоянию элемента управления до продолжения через замыкание.
За пределами Controller
у нас нет доступа к этому ControllerContext
поэтому мы должны использовать работающий System.Web.HttpContext
который имеет все предостережения с ConfigureAwait(false);
,