У меня есть следующий тестовый код WebAPI, я не использую WebAPI в производстве, но я сделал это из-за обсуждения, которое у меня было по этому вопросу: Вопрос об асинхронности WebAPI
В любом случае, вот оскорбительный метод WebAPI:
public async Task<string> Get(int id)
{
var x = HttpContext.Current;
if (x == null)
{
// not thrown
throw new ArgumentException("HttpContext.Current is null");
}
await Task.Run(() => { Task.Delay(500); id = 3; });
x = HttpContext.Current;
if (x == null)
{
// thrown
throw new ArgumentException("HttpContext.Current is null");
}
return "value";
}
До сих пор я полагал, что ожидается второе исключение, потому что после await
завершения оно, вероятно, будет в другом потоке, где HttpContext.Current
статическая переменная потока больше не будет разрешаться в соответствующее значение. Теперь, исходя из контекста синхронизации, его можно заставить вернуться к тому же потоку после ожидания, но я не делаю ничего необычного в своем тесте. Это просто простое, наивное использование await
.
В комментариях к другому вопросу мне сказали, что это HttpContext.Current
должно разрешиться после ожидания. Есть даже еще один комментарий по этому вопросу, указывающий на то же самое. Так что правда? Должен ли он разрешиться? Думаю , что нет, но я хочу , авторитетный ответ на это , потому что async
и await
это достаточно новый , что я не могу найти ничего окончательного.
TL; DR: HttpContext.Current
потенциально null
после await
?
источник
AspNetSynchronizationContext
о чем заботятсяHttpContext
, а неawait
. Более того, обратный вызов продолжения дляawait
может (и, скорее всего, будет) происходить в другом потоке для модели выполнения веб-API..ConfigureAwait(false)
где-то работает. Нет никакого запроса или контроллера, явно передаваемого через бизнес-уровень, поскольку он не поддерживает веб. Это полезно, например, для модуля ведения журнала, который может вводить детали запроса, когда бизнес-логика записывает общийTraceInformation
.Ответы:
Убедитесь, что вы пишете приложение ASP.NET 4.5 и ориентируетесь на 4.5.
async
иawait
имеют неопределенное поведение в ASP.NET, если вы не работаете в 4.5 и не используете новый «удобный для задач» контекст синхронизации.В частности, это означает, что вы должны:
httpRuntime.targetFramework
на4.5
, илиappSettings
установитеaspnet:UseTaskFriendlySynchronizationContext
значениеtrue
.Более подробная информация доступна здесь .
источник
<httpRuntime targetFramework="4.5" />
что решается, спасибо за разъяснение.targetFramework
4.5.1 или 4.5, но async на 4.5.1 должен работать нормально.Как правильно указал @StephenCleary, вам нужно это в вашем web.config:
<httpRuntime targetFramework="4.5" />
Когда я впервые занимался устранением неполадок, я выполнил поиск вышеуказанного решения по всему решению, подтвердил, что он присутствует во всех моих веб-проектах, и быстро отклонил его как виновника. В конце концов мне пришло в голову взглянуть на эти результаты поиска в полном контексте:
<!-- For a description of web.config changes for .NET 4.5 see http://go.microsoft.com/fwlink/?LinkId=235367. The following attributes can be set on the <httpRuntime> tag. <system.Web> <httpRuntime targetFramework="4.5" /> </system.Web> -->
Дох.
Урок: если вы обновляете веб-проект до версии 4.5, вам все равно нужно установить этот параметр вручную.
источник
Ваш тест не содержит ошибок, и HttpContext.Current не должен иметь значение null после ожидания, потому что в веб-API ASP.NET, когда вы ожидаете, это гарантирует, что код, следующий за этим ожиданием, будет передан правильному HttpContext, который присутствовал до ожидания.
источник
Я недавно столкнулся с этой проблемой. Как отметил Стивен, отсутствие явной настройки целевой структуры может вызвать эту проблему.
В моем случае наш веб-API был перенесен в версию 4.6.2, но целевая среда выполнения никогда не была указана в веб-конфигурации, поэтому в основном это отсутствовало внутри тега <system.web>:
Если у вас есть сомнения по поводу используемой вами версии фреймворка, это может помочь: добавьте следующую строку в любой из ваших методов веб-API и установите точку останова, чтобы проверить, какой тип в настоящее время загружается во время выполнения, и убедиться, что это не реализация Legacy:
Вы должны увидеть это (AspNetSynchronizationContext):
Вместо LegazyAspNetSynchronizationContext (что я видел перед добавлением целевой платформы):
Если вы перейдете к исходному коду ( https://referencesource.microsoft.com/#system.web/LegacyAspNetSynchronizationContext.cs ), вы увидите, что в устаревшей реализации этого интерфейса отсутствует поддержка асинхронности.
Я потратил много времени, пытаясь найти источник проблемы, и ответ Стивена мне очень помог. Надеюсь, этот ответ предоставит дополнительную информацию о проблеме.
источник