Was ist die richtige Signatur für eine Controller-Aktion, die ein IAsyncEnumerable<T>
und ein zurückgibt, NotFoundResult
aber dennoch asynchron verarbeitet wird?
Ich habe diese Signatur verwendet und sie wird nicht kompiliert, weil sie IAsyncEnumerable<T>
nicht erwartet werden kann:
[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);
}
}
Dieser kompiliert gut, aber seine Signatur ist nicht asynchron. Ich mache mir also Sorgen, ob Thread-Pool-Threads blockiert werden oder nicht:
[HttpGet]
public IActionResult GetAll(Guid id)
{
try
{
return Ok(repository.GetAll(id)); // GetAll() returns an IAsyncEnumerable
}
catch (NotFoundException e)
{
return NotFound(e.Message);
}
}
Ich habe versucht, eine await foreach
Schleife wie diese zu verwenden, aber das würde natürlich auch nicht kompiliert:
[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
Friedrich der Narr
quelle
quelle
MyObject
Artikel mit demselben zurückid
? Normalerweise würden Sie keineNotFound
für etwas senden, das eine zurückgibtIEnumerable
- es wäre nur leer - oder Sie würden den einzelnen Artikel mit dem angefordertenid
/ zurückgebenNotFound
.IAsyncEnumerable
ist zu erwarten. Verwenden Sieawait foreach(var item from ThatMethodAsync()){...}
.IAsyncEnumerable<MyObject>
einfach das Ergebnis zurück, zreturn objects
. Dass nicht eine HTTP - Aktion zu einer Streaming - gRPC oder SignalR Methode obwohl konvertieren. Die Middleware verbraucht weiterhin die Daten und sendet eine einzelne HTTP-Antwort an den ClientIAsyncEnumerable
ab 3.0 bekannt.Antworten:
Option 2, die eine Implementierung von
IAsyncEnumerable<>
in denOk
Aufruf übergibt , ist in Ordnung. Das ASP.NET Core-Sanitär kümmert sich um die Aufzählung und istIAsyncEnumerable<>
ab 3.0 bekannt.Hier ist der Aufruf der Frage, der für den Kontext wiederholt wird:
Der Aufruf zum
Ok
Erstellen einer Instanz vonOkObjectResult
, die erbtObjectResult
. Der übergebene WertOk
ist vom Typobject
, der in der Eigenschaft vonObjectResult
'' enthalten istValue
. ASP.NET Core MVC verwendet das Befehlsmuster , wobei der Befehl eine Implementierung von istIActionResult
und unter Verwendung einer Implementierung von ausgeführt wirdIActionResultExecutor<T>
.Für
ObjectResult
,ObjectResultExecutor
wird die verwendete drehenObjectResult
in eine HTTP - Antwort. Es ist die Implementierung vonObjectResultExecutor.ExecuteAsync
das istIAsyncEnumerable<>
-Aware:Wie der Code zeigt, wird die
Value
Eigenschaft überprüft, um festzustellen, ob sie implementiert istIAsyncEnumerable<>
(die Details sind im Aufruf von verborgenTryGetReader
). Wenn dies der Fall ist,ExecuteAsyncEnumerable
wird aufgerufen, wodurch die Aufzählung durchgeführt und das aufgezählte Ergebnis an Folgendes übergeben wirdExecuteAsyncCore
:reader
Im obigen Snippet erfolgt die Aufzählung. Es ist ein wenig begraben, aber Sie können die Quelle sehen hier sehen :Das
IAsyncEnumerable<>
wird in einemList<>
using aufgezähltawait foreach
, das fast per Definition keinen Anfragethread blockiert. Wie Panagiotis Kanavos in einem Kommentar zum OP ausführte, wird diese Aufzählung zuvor vollständig durchgeführt eine Antwort an den Client zurückgesendet wird.quelle
Task
Objekt zurückgibt. Behindert diese Tatsache selbst in irgendeiner Weise die Asynchronität? Besonders im Vergleich zu einer ähnlichen Methode, die a zurückgabTask
.Task
, da die Methode selbst keine asynchrone Arbeit ausführt. Es ist die asynchrone Aufzählung, die wie oben beschrieben behandelt wird. Sie können sehen, dassTask
dort bei der Ausführung der verwendet wirdObjectResult
.