Jaki jest prawidłowy podpis dla akcji kontrolera, która zwraca IAsyncEnumerable<T>
i a, NotFoundResult
ale jest nadal przetwarzana w sposób asynchroniczny?
Użyłem tego podpisu i nie można go skompilować, ponieważ IAsyncEnumerable<T>
nie jest to oczekiwane:
[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);
}
}
Ten kompiluje się dobrze, ale jego podpis nie jest asynchroniczny. Martwię się więc, czy zablokuje wątki puli wątków, czy nie:
[HttpGet]
public IActionResult GetAll(Guid id)
{
try
{
return Ok(repository.GetAll(id)); // GetAll() returns an IAsyncEnumerable
}
catch (NotFoundException e)
{
return NotFound(e.Message);
}
}
Próbowałem użyć await foreach
pętli w ten sposób, ale to oczywiście nie skompiluje:
[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
Frederick The Fool
źródło
źródło
MyObject
przedmiotów z tym samymid
? Zwykle nie wysyłałbyśNotFound
za coś, co zwracaIEnumerable
- byłby po prostu pusty - lub zwracałbyś pojedynczy przedmiot z żądanymid
/NotFound
.IAsyncEnumerable
jest oczekiwany. Zastosowanieawait foreach(var item from ThatMethodAsync()){...}
.IAsyncEnumerable<MyObject>
, po prostu zwróć wynik, npreturn objects
. Że nie będzie konwertować działanie HTTP streaming gRPC lub SignalR metody chociaż. Oprogramowanie pośrednie nadal będzie pobierać dane i wysyłać pojedynczą odpowiedź HTTP do klientaIAsyncEnumerable
od wersji 3.0.Odpowiedzi:
Wariant 2, która przechodzi implementację
IAsyncEnumerable<>
doOk
rozmowy, jest w porządku. Instalacja hydrauliczna programu ASP.NET Core zajmuje się wyliczaniem i jest dostępnaIAsyncEnumerable<>
od wersji 3.0.Oto wezwanie z pytania, powtórzone dla kontekstu:
Wywołanie do
Ok
tworzy instancjęOkObjectResult
, która dziedziczyObjectResult
. Wartość przekazana w celuOk
jest typuobject
, który odbywa się wObjectResult
„sValue
nieruchomości. ASP.NET Core MVC używa wzorca polecenia , przy czym polecenie jest implementacjąIActionResult
i jest wykonywane przy użyciu implementacjiIActionResultExecutor<T>
.Na
ObjectResult
,ObjectResultExecutor
jest używany, aby włączyćObjectResult
do odpowiedzi HTTP. Jest to realizacja stanowiObjectResultExecutor.ExecuteAsync
toIAsyncEnumerable<>
-aware:Jak pokazuje kod,
Value
właściwość jest sprawdzana pod kątem implementacjiIAsyncEnumerable<>
(szczegóły są ukryte w wywołaniu doTryGetReader
). Jeśli tak,ExecuteAsyncEnumerable
jest wywoływany, który wykonuje wyliczenie, a następnie przekazuje wyliczony wynik doExecuteAsyncCore
:reader
w powyższym fragmencie znajduje się miejsce, w którym występuje wyliczenie. Jest trochę pochowany, ale możesz zobaczyć źródło tutaj :Jest
IAsyncEnumerable<>
on wyliczany na wartośćList<>
usingawait foreach
, która prawie z definicji nie blokuje wątku żądania. Jak Panagiotis Kanavos zawołał w komentarzu do PO, wyliczenie to jest wykonywane w całości przed odesłaniem odpowiedzi do klienta.źródło
Task
obiektu. Czy sam fakt w jakikolwiek sposób utrudnia asynchroniczność? Zwłaszcza w porównaniu do, powiedzmy, podobnej metody, która zwróciła aTask
.Task
, ponieważ sama metoda nie wykonuje żadnej pracy asynchronicznej. Jest to wyliczenie asynchroniczne, które jest obsługiwane jak opisano powyżej. Możesz zobaczyć, żeTask
jest tam używany, podczas wykonywaniaObjectResult
.