Могу ли я заблокировать асинхронный код в MVC Core?

Мы все знаем знаменитое сообщение в блоге относительно блокировки асинхронного кода Стивеном Клири. В MVC 5 следующий код блокируется при запросе Home/Index:

public class HomeController : Controller
{
    public string Index()
    {
        var model = AsyncMethod();
        return model.Result;
    }

    private async Task<string> AsyncMethod()
    {
        await Task.Run(() => Thread.Sleep(2000));
        return "Hello";
    }
}

Однако тот же самый код не заторможен в веб-приложении MVC Core. Ответ возвращает Hello. Зачем? Поддерживает ли MVC Core несколько потоков одновременно работать в одном контексте запроса? Является ли фраза Не блокировать асинхронный код устаревшей при разработке в MVC Core?

Ответ 1

Почему?

Ядро ASP.NET async сверху вниз, и оно предназначено для максимальной скорости.

В рамках редизайна команда ASP.NET смогла полностью удалить весь AspNetSynchronizationContext. Некоторые аспекты контекста запроса ASP.NET были перенесены в основное .NET, а другие были просто удалены (например, HttpContext.Current).

Поддерживает ли MVC Core несколько потоков одновременно в одном контексте запроса?

Нет. Однако понятие "контекст запроса" больше не представлено контекстом синхронизации.

Является ли "Не блокировать фразу" Асинхронный код "устаревшей при разработке в MVC Core?

Нет. Он не будет зациклен на ядре ASP.NET, но вы все равно не должны этого делать.

"Могу ли я заблокировать асинхронный код в MVC Core?" Да. "Должен ли я блокировать асинхронный код в MVC Core?" Нет.

Ответ 2

Этот код

await Task.Run(() => Thread.Sleep(2000));

не может быть отличным шаблоном, но он не "блокирует" в том же смысле, что и ссылка Стивена. Чтобы сравнить яблоки с яблоками, вам нужно будет сделать это:

private string BlockingAsyncMethod()
{
    Task.Run(() => Thread.Sleep(2000)).Wait();
    return "Hello";
}

Блокировка на Wait() или .Result является большим no-no для MVC 5. Насколько мне известно, это все еще правильный совет для MVC Core.