Перейти к содержанию

Генерация ответа от модели

Рассмотрим сценраий: создаем метод действия веб-API для возврата списка автомобилей:

[ApiController]
public class CarsController : Controller
{
    [HttpGet("api/cars")]
    public IEnumerable<string> ListCars()
    {
        return new string[] { "Nissan Micra", "Ford Focus" };
    }
}

Как мы обсуждали, можно возвращать данные непосредственно из метода действия, и промежуточное ПО отформатирует их и передаст клиенту. Как оно узнает, какой формат использовать?
Процесс определения формата данных известен как согласование содержимого (content negotiation — conneg). В общих чертах это работает так: клиент отправляет типы контента, которые он может понять, в заголовке Accept, а сервер выбирает один из них, форматирует ответ и отправляет в ответе заголовок content-type с указанием выбранного типа.
Когда возвращается модель API, независимо от того, делается это напрямую или через OkResult (или любой другой StatusCodeResult), и если ASP.NET Core не может вернуть результат в формате, указанном в Accept, будет использован формат JSON по умолчанию.
Данные всегда сериализуются при помощи одной из реализаций IOutputFormatter.

Настройка форматтеров по умолчанию — добавляем поддержку XML

По умолчанию настроены только форматтеры text/plain, text/html и application/json. Чтобы добавить вывод XML, нужно добавить форматтер вывода1. Для этого нужно настроить объект IMvcBuilder, возвращаемый из метода AddControllers:

services.AddControllers().AddXmlSerializerFormatters();

Теперь передача заголовка Accept: "text/xml" будет приводить к сериализации в XML.

Выбор формата с помощью согласования содержимого

Согласование содержимого (content negotiation) — это когда клиент сообщает, какие типы данных он может принимать, используя заголовок Accept, а сервер выбирает наиболее подходящий из них, который он может обработать. В целом, это так и работает, но в реализаци ASP.NET Core есть несколько особых случаев, которые нужно учитывать:

  • по умолчанию возвращаются только MIME-типы application/json, text/plain и text/html. Можно добавить другие форматтеры IOutputFormatter;
  • по умолчанию, если в качестве модели API возвращается null, как напрямую, так и через StatusCodeResult, промежуточное ПО вернет ответ 204 No Content;
  • если в качестве модели API возвращается строка, и не задан заголовок Accept, ответ отформатируется как text/plain;
  • если используется любой другой класс и либо отсутствует заголовок Accept, либо запрашиваются только неподдерживаемые форматы, будет использоваться первый форматтер, который может сгенерировать ответ (обычно JSON);
  • если промежуточное ПО обнаружит, что запрос, вероятно, исходит от браузера (Accept содержит */*), то согласование содержимого не будет использоваться, ответ будет отформатирован как если бы Accept не был передан.

Эти правила можно настроить, например, в примере показано, как заставить промежуточное ПО учитывать браузерный Accept и удалить форматтер text/plain для строк:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options =>
    {
        options.RespectBrowserAcceptHeader = true;
        options.OutputFormatters.RemoveType<StringOutputFormatter>();
    });
}

Дополнительные сведения, в том числе и об обходе обычных механизмов согласования содержимого можно найти в документации Microsoft


  1. Технически таким образом добавляется и форматтер ввода XML, что означает, что теперь приложение может получать XML в запросах. Подробно о форматтерах, включая создание собственного, см. в документации 


Последнее обновление : 21 апреля 2023 г.
Дата создания : 28 сентября 2022 г.

Комментарии

Комментарии