AspNet.Core возвращает 200 OK и недействительный Json, если во время итерации IEnumerable возникает исключение (возвращается из контроллера) - PullRequest
4 голосов
/ 21 марта 2019

Кажется, что AspNet.Core начинает отправлять ответ, который IEnumerable сразу, без перебора всей коллекции.Например:

[HttpGet("")]
public async Task<IActionResult> GetData()
{
    IEnumerable<MyData> result = await _service.GetData();
    return Ok(result.Select(_mapper.MapMyDataToMyDataWeb));
}

Теперь существует исключение, которое происходит во время отображения одного из элементов, поэтому я бы предположил, что ответ 500, но в действительности получается, что я получаю 200 столько частичный (и неправильный) Json.

Я предполагаю, что это функция, а не ошибка в Asp.Net Core, обеспечивающая такое поведение, и ее относительно легко исправить, например, с помощью ToList(), но мне интересноесли есть какой-то флаг, который может предотвратить возникновение этой ситуации, поскольку он не имеет смысла, например, для проекта API и стандартного ответа JSON.

Я не смог найти ничего в документации, которая описывает это поведение икак это предотвратить.

PS Я проверил, что вызов ToList() устраняет проблему, и ответ 500 с правильным исключением (с UseDeveloperExceptionPage)

1 Ответ

5 голосов
/ 21 марта 2019

Кажется, что это на самом деле "намеренно", эта проблема была несколько раз поднята в репозитории Asp.Net Core github.

Что происходит, так это то, что заголовок с 200 уже отправлен, а тело нет. Хотя я думаю, что перечисление должно продолжаться до отправки заголовков, команда asp.net говорит, что будет использовать больше ресурсов на сервере, и именно поэтому это так.

Вот цитата:

Весьма вероятно, что ваше исключение выдается при записи к телу, после того, как заголовки уже отправлены клиенту, так нет никаких возвратов на 200, который уже был отправлен как часть ответ. Клиент увидит ошибку, потому что тело вернется как неполный.

Если вы хотите детерминистически сообщить 500, когда это произойдет, вы нужно либо:

  • Буферизировать ваш IEnumerable как часть действия (.ToList ())
  • Буфер тела ответа - https://github.com/aspnet/BasicMiddleware/tree/dev/src/Microsoft.AspNetCore.Buffering Очевидно, что обе эти вещи требуют больше ресурсов на стороне сервера, вот почему у нас нет такого поведения по умолчанию.

Я могу подтвердить, что это решение работало:

  1. Ссылка Microsoft.AspNetCore.Buffering Упаковка
  2. Пишите app.UseResponseBuffering() до app.UseMvc()
...