Как установить код состояния 404 при возврате пустого IAsyncEnumerable в ASP.NET Ядро (.NET 6)

#c# #asp.net-core-6.0

Вопрос:

У меня есть действие контроллера, которое возвращает значение IAsyncEnumerable. Он запрашивает источник данных, и если данные доступны, каждый результат «возвращает доходность»(сериализуется System.Text.Json и возвращен клиенту). Но как я могу установить код состояния на 404, если результаты недоступны? Прямо сейчас, если результаты недоступны, метод возвращает пустой массив JSON с кодом состояния = 200.

 public async IAsyncEnumerable<string> GetStrings()
{
    IEnumerable<string> stringResults = await myData.GetStringsAsync();

    if (stringResults is object amp;amp; stringResults.Any())
    {
        foreach (string result in stringResults)
        {
            yield return resu<
        }
    }
    else
    {
        return NotFound(); //CS1622: Cannot return a value from an iterator....
    }
}
 

Обновить

Я хочу, чтобы эта потоковая передача была передана клиенту, как только появятся результаты. Если я вернусь Task<IEnumerable<string>> , то весь список/массив/коллекция должны быть заполнены до передачи в System.Text.Json для сериализации. Я не думаю, что это очень эффективно для памяти.

Комментарии:

1. @Общее, если оно равно нулю?

2. IAsyncEnumerable не сделает синхронный метод асинхронным. Почему вы им пользуетесь?

3. Я хочу, чтобы эта потоковая передача была передана клиенту, как только появятся результаты. Если я возвращаю задачу<IEnumerable<строка><строка>>, то весь список/массив/коллекция должны быть заполнены перед передачей в System.Text. Json для сериализации. Я не думаю, что это очень эффективно для памяти.

4. async Task<IActionResult> GetStrings() ... return Ok(stringResults); однако вызов .Any() приведет к тому, что коллекция будет перечислена дважды.

5. Если await myData.GetStringsAsync возвращается IEnumerable , действительно ли это возвращает a List ? В каком случае у вас уже есть все результаты? Или этот метод передает результаты синхронно?

Ответ №1:

Вы не можете смешивать асинхронный генератор и возвращаемое действие mvc NotFound() . Но вы можете написать два метода.

 public async Task<IActionResult> GetStrings()
{
    IEnumerable<string> stringResults = await myData.GetStringsAsync();
    if (stringResults == null)
        return NotFound();
    var e = stringResults.GetEnumerator();
    if (!e.MoveNext())
        return NotFound();
    return Ok(AsEnum(e));

    async IAsyncEnumerable<string> AsEnum(IEnumerator<string> e){
        do {
            yield return e.Current;
        } while (e.MoveNext());
    }
}
 

С любой дополнительной обработкой ошибок и удалением перечислителя.

Однако здесь все еще есть разница в поведении. В отличие async Task от метода, IEnumerable IAsyncEnumerable методы amp; generator не запускаются до первого вызова .MoveNext[Async] .

Поскольку ваша предыдущая реализация возвращала IAsyncEnumerable бы значение в MVC перед выполнением любого из ваших действий. Заголовки HTTP будут записаны , и сериализатор json вызовет IAsyncEnumerable.MoveNextAsync их еще до GetStringAsync того, как будет вызвана ваша служба.

Если вы хотите дождаться первого результата, прежде чем возвращать 200/404, вам придется подождать, пока серверная служба вернет что-то, прежде чем вы сможете написать какие-либо заголовки HTTP.

Использование времени до первого байта в качестве показателя здесь полностью вводит в заблуждение.

Комментарии:

1. Спасибо за ответ. К сожалению, это все равно приводит к задержке TTFB (т. Е. не потоковой передаче). Также я думаю, что вы имели в виду IActionResult вместо IAsyncResult. Таким образом, похоже, что если я захочу установить код состояния, то я не смогу транслировать.

2. Как мы уже говорили, если ваши исходные данные на самом деле не передаются в потоковом режиме, вы можете не заметить, передаются ли выходные данные в потоковом режиме. Является ли транспортная кодировка ответа фрагментированной? В то время как ваш предыдущий пример, возможно, сразу же запустил заголовки ответов и » [ » , прежде чем вы смогли определить, были ли результаты пустыми. Фактические результаты были бы написаны в аналогичное время. Таким образом, ваш TTFB может вводить в заблуждение.