Какова правильная подпись для действия контроллера, которое возвращает IAsyncEnumerable<T>
и, NotFoundResult
но все еще обрабатывается асинхронно?
Я использовал эту подпись, и она не компилируется, потому что IAsyncEnumerable<T>
не является ожидаемой:
[HttpGet]
public async Task<IActionResult> GetAll(Guid id)
{
try
{
return Ok(await repository.GetAll(id)); // GetAll() returns an IAsyncEnumerable
}
catch (NotFoundException e)
{
return NotFound(e.Message);
}
}
Этот компилируется нормально, но его подпись не асинхронная. Так что я волнуюсь, заблокирует ли он потоки пула потоков или нет:
[HttpGet]
public IActionResult GetAll(Guid id)
{
try
{
return Ok(repository.GetAll(id)); // GetAll() returns an IAsyncEnumerable
}
catch (NotFoundException e)
{
return NotFound(e.Message);
}
}
Я попытался использовать await foreach
цикл таким образом, но он, очевидно, тоже не скомпилируется:
[HttpGet]
public async IAsyncEnumerable<MyObject> GetAll(Guid id)
{
IAsyncEnumerable<MyObject> objects;
try
{
objects = contentDeliveryManagementService.GetAll(id); // GetAll() returns an IAsyncEnumerable
}
catch (DeviceNotFoundException e)
{
return NotFound(e.Message);
}
await foreach (var obj in objects)
{
yield return obj;
}
}
c#
asp.net-core
async-await
asp.net-core-mvc
Фредерик Дурак
источник
источник
MyObject
предметов с одинаковымиid
? Обычно вы не отправляетеNotFound
что-то, что возвращаетIEnumerable
- оно будет пустым - или вы возвращаете один элемент с запрошеннымid
/NotFound
.IAsyncEnumerable
ожидаемо. Использованиеawait foreach(var item from ThatMethodAsync()){...}
.IAsyncEnumerable<MyObject>
, просто верните результат, напримерreturn objects
. Это не преобразует действие HTTP в потоковый gRPC или метод SignalR. Промежуточное программное обеспечение будет по-прежнему потреблять данные и отправлять клиенту один HTTP-ответIAsyncEnumerable
поддерживает версии 3.0.Ответы:
Вариант 2, который передает реализацию
IAsyncEnumerable<>
вOk
вызов, подойдет. Сантехническое оборудование ASP.NET Core заботится о перечислении иIAsyncEnumerable<>
поддерживает версии 3.0.Вот ответ на вопрос, повторенный для контекста:
Вызов
Ok
создает экземплярOkObjectResult
, который наследуетсяObjectResult
. Значение , переданное вOk
имеет типobject
, который проходит вObjectResult
«SValue
собственности. ASP.NET Core MVC использует шаблон команды , в которой команда является реализациейIActionResult
и выполняется с использованием реализацииIActionResultExecutor<T>
.Для
ObjectResult
,ObjectResultExecutor
используется, чтобы превратитьObjectResult
в ответ HTTP. Это реализация того,ObjectResultExecutor.ExecuteAsync
чтоIAsyncEnumerable<>
-aware:Как показывает код,
Value
свойство проверяется, чтобы увидеть, реализует ли оноIAsyncEnumerable<>
(подробности скрыты в вызовеTryGetReader
). Если это так,ExecuteAsyncEnumerable
вызывается, который выполняет перечисление, а затем передает перечисленный результат вExecuteAsyncCore
:reader
в приведенном фрагменте, где происходит перечисление. Это похоронено немного, но вы можете увидеть источник здесь :IAsyncEnumerable<>
Перечисляется вList<>
использованииawait foreach
, что, почти по определению, не блокирует поток запроса. Как Panagiotis Kanavos выкрикнул в комментарии к OP, это перечисление выполняется полностью перед отправкой ответа клиенту.источник
Task
объект. Этот факт сам по себе мешает асинхронности каким-либо образом? Особенно по сравнению, скажем, с аналогичным методом, который возвращаетTask
.Task
, поскольку сам метод не выполняет асинхронную работу. Это перечисление асинхронное, которое обрабатывается, как описано выше. Вы можете видеть, чтоTask
используется там, в исполненииObjectResult
.