Вызов 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); ,