¿Cuál es la firma correcta para una acción de controlador que devuelve un IAsyncEnumerable<T>y a NotFoundResultpero que aún se procesa de forma asíncrona?
IAsyncEnumerable<T>Usé esta firma y no se compila porque no está a la espera:
[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);
}
}
Este se compila bien pero su firma no es asíncrona. Entonces me preocupa si bloqueará los hilos del grupo de hilos o no:
[HttpGet]
public IActionResult GetAll(Guid id)
{
try
{
return Ok(repository.GetAll(id)); // GetAll() returns an IAsyncEnumerable
}
catch (NotFoundException e)
{
return NotFound(e.Message);
}
}
Intenté usar un await foreachbucle como este, pero eso obviamente tampoco compilaría:
[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
Federico el tonto
fuente
fuente

MyObjectartículos con lo mismoid? Normalmente, no enviaría unNotFoundpor algo que devuelve unIEnumerable, simplemente estaría vacío, o devolvería el artículo individual con elid/ solicitadoNotFound.IAsyncEnumerableEstá a la espera. Usoawait foreach(var item from ThatMethodAsync()){...}.IAsyncEnumerable<MyObject>, simplemente devuelva el resultado, por ejemploreturn objects. Sin embargo, eso no convertirá una acción HTTP en un método gRPC o SignalR de transmisión. El middleware seguirá consumiendo los datos y enviará una única respuesta HTTP al clienteIAsyncEnumerableconocimiento de 3.0.Respuestas:
La opción 2, que pasa una implementación
IAsyncEnumerable<>a laOkllamada, está bien. La fontanería ASP.NET Core se encarga de la enumeración y tieneIAsyncEnumerable<>conocimiento de 3.0.Aquí está la llamada de la pregunta, repetida para el contexto:
La llamada a
Okcrea una instancia deOkObjectResult, que heredaObjectResult. El valor pasado aOkes de tipoobject, que se celebra en elObjectResult'sValuepropiedad. ASP.NET Core MVC usa el patrón de comando , mediante el cual el comando es una implementación deIActionResulty se ejecuta usando una implementación deIActionResultExecutor<T>.Para
ObjectResult,ObjectResultExecutorse utiliza para convertir elObjectResulten una respuesta HTTP. Es la implementación deObjectResultExecutor.ExecuteAsynceso esIAsyncEnumerable<>-aware:Como muestra el código, la
Valuepropiedad se verifica para ver si se implementaIAsyncEnumerable<>(los detalles están ocultos en la llamada aTryGetReader). Si lo hace,ExecuteAsyncEnumerablese llama, que realiza la enumeración y luego pasa el resultado enumerado aExecuteAsyncCore:readeren el fragmento anterior es donde ocurre la enumeración. Está enterrado un poco, pero puedes ver la fuente aquí :El
IAsyncEnumerable<>se enumera en unList<>usoawait foreach, que, casi por definición, no bloquea un hilo de solicitud. Como Panagiotis Kanavos llamó en un comentario sobre el OP, esta enumeración se realiza en su totalidad antes de que se envíe una respuesta al cliente.fuente
Taskobjeto. ¿Ese hecho en sí mismo obstaculiza la asincronía de alguna manera? Especialmente comparado con, digamos, un método similar que devolvió aTask.Task, porque el método en sí no realiza ningún trabajo asincrónico. La enumeración es asincrónica, que se maneja como se describe anteriormente. Puede ver queTaskse usa allí, en la ejecución deObjectResult.