Форматирование данных отклика в веб-API ASP.NET Core

ASP.NET Core MVC поддерживает форматирование данных ответа, используя указанные форматы или в ответ на запрос клиента.

Результаты действий для конкретного формата

Некоторые типы результатов действий характерны для определенного формата, например JsonResult и ContentResult. Действия могут возвращать результаты, которые всегда используют указанный формат, игнорируя запрос клиента для другого формата. Например, возврат возвращаемых JsonResultJSданных в формате ON и возврат ContentResult возвращает данные строки с форматом обычного текста.

Действие не должно возвращать данные конкретного типа. ASP.NET Core поддерживает любое возвращаемое значение объекта. Результаты действий, возвращающих объекты, которые не IActionResult являются типами, сериализуются с помощью соответствующей IOutputFormatter реализации. Дополнительные сведения см. в разделе "Типы возвращаемых действий контроллера" в веб-API ASP.NET Core.

По умолчанию встроенный вспомогательный метод ControllerBase.Ok возвращает JSданные в формате ON:

[HttpGet]
public IActionResult Get() =>
    Ok(_todoItemStore.GetList());

Пример кода возвращает список элементов todo. С помощью средств разработчика браузера F12 или http-repl с предыдущим кодом отображается следующее:

  • Заголовок ответа, содержащий тип контента:application/json; charset=utf-8.
  • Заголовки запроса. Например, заголовок Accept. Приведенный выше код игнорирует заголовок Accept.

Чтобы возвратить данные в формате обычного текста, используйте ContentResult и вспомогательный метод Content:

[HttpGet("Version")]
public ContentResult GetVersion() =>
    Content("v1.0.0");

В приведенном выше коде возвращаемым Content-Type является text/plain.

Для действий с несколькими возвращаемыми типами возвращается значение IActionResult. Например, при возврате различных кодов состояния HTTP в зависимости от результата операции.

Согласование содержимого

Согласование содержимого происходит, когда клиент задает заголовок Accept. Формат по умолчанию, используемый ASP.NET Core, имеет значение JSON. Согласование содержимого:

  • реализуется с помощью ObjectResult;
  • встроено в результаты действия с определенным кодом состояния, возвращаемые из вспомогательных методов; вспомогательные методы результатов действия основаны на ObjectResult;

при возврате типа модели возвращаемым типом является ObjectResult.

Следующий метод действия использует вспомогательные методы Ok и NotFound:

[HttpGet("{id:long}")]
public IActionResult GetById(long id)
{
    var todo = _todoItemStore.GetById(id);

    if (todo is null)
    {
        return NotFound();
    }

    return Ok(todo);
}

По умолчанию ASP.NET Core поддерживает следующие типы носителей:

  • application/json
  • text/json
  • text/plain

Средства, такие как Fiddler или Postman, могут установить заголовок запроса Accept, чтобы указать формат возвращаемого значения. Если заголовок Accept содержит тип, который поддерживается сервером, возвращается этот тип. Сведения о добавлении дополнительных форматировщиков приведены в следующем разделе.

Действия контроллера могут возвращать POCO (простые объекты CLR). При возвращении POCO среда выполнения автоматически создает ObjectResult, который генерирует оболочку объекта. Клиент получает отформатированный сериализованный объект. Если возвращаемый объект имеет значение null, возвращается ответ 204 No Content.

В следующем примере возвращается тип объекта:

[HttpGet("{id:long}")]
public TodoItem? GetById(long id) =>
    _todoItemStore.GetById(id);

В приведенном выше коде запрос допустимого элемента todo возвращает 200 OK ответ. Запрос недопустимого элемента todo возвращает 204 No Content ответ.

Заголовок Accept

Согласование содержимого выполняется только при наличии в запросе заголовка Accept. Если запрос содержит заголовок Accept, ASP.NET Core:

  • перечисляет типы мультимедиа в заголовке Accept в порядке предпочтения;
  • пытается найти форматировщик, который может создать ответ в одном из указанных форматов.

Если форматировщик, который может удовлетворить запрос клиента, не найден, ASP.NET Core:

  • Возвращает значение 406 Not Acceptable , если MvcOptions.ReturnHttpNotAcceptable задано значение true, или -
  • пытается найти первый форматировщик, который может создать ответ.

Если форматировщик, обеспечивающий требуемый формат, не настроен, используется первый форматировщик, способный отформатировать данный объект. Если в запросе не отображается заголовок Accept:

  • Для сериализации ответа используется первый форматировщик, который может работать с объектом.
  • Согласование не выполняется. Сервер определяет возвращаемый формат.

Если заголовок Accept содержит */*, он игнорируется, если только RespectBrowserAcceptHeader не имеет значение true в MvcOptions.

Браузеры и согласование содержимого

В отличие от обычных клиентов API, веб-браузеры предоставляют заголовки Accept. Веб-браузеры указывают множество форматов, включая дикие карта. Если платформа обнаруживает, что запрос поступает из браузера, по умолчанию выполняется следующее:

  • Заголовок Accept игнорируется.
  • Содержимое возвращается в JSON, если иное не настроено.

Этот подход обеспечивает более согласованный интерфейс в браузерах при использовании API.

Чтобы настроить приложение для соблюдения заголовков браузера, задайте RespectBrowserAcceptHeader для свойства trueзначение :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers(options =>
{
    options.RespectBrowserAcceptHeader = true;
});

Настройка форматировщиков

Приложения, которые должны поддерживать дополнительные форматы, могут добавлять соответствующие пакеты NuGet и настраивать поддержку. Существуют отдельные модули форматирования для ввода и вывода. Форматировщики ввода используются привязкой модели. Форматировщики вывода используются для форматирования ответов. Сведения о создании пользовательского форматировщика см. в статье Пользовательские модули форматирования для веб-API в ASP.NET Core.

Добавление поддержки формата XML

Чтобы настроить xml-форматировщики, реализованные с помощью , XmlSerializerвызов:AddXmlSerializerFormatters

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .AddXmlSerializerFormatters();

При использовании приведенного выше кода методы контроллера возвращают соответствующий формат на основе заголовка Accept запроса.

Настройка System.Text.Jsonформатировщиков на основе

Чтобы настроить функции для System.Text.Jsonформатировщиков на основе, используйте Microsoft.AspNetCore.Mvc.JsonOptions.JsonSerializerOptions. Следующий выделенный код настраивает форматирование PascalCase вместо форматирования верблюдьего Регистра по умолчанию:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.PropertyNamingPolicy = null;
    });

Для создания ProblemDetails ответа вызывается ControllerBase.Problem следующий метод действия:

[HttpGet("Error")]
public IActionResult GetError() =>
    Problem("Something went wrong.");

ProblemDetails Ответ всегда верблюдю Регистр, даже если приложение задает формат PascalCase. ProblemDetailsследует RFC 7807, который задает нижний регистр.

Чтобы настроить параметры сериализации выходных данных для определенных действий, используйте JsonResult. Например:

[HttpGet]
public IActionResult Get() =>
    new JsonResult(
        _todoItemStore.GetList(),
        new JsonSerializerOptions
        {
            PropertyNamingPolicy = null
        });

Добавление Newtonsoft.Jsonподдержки JSформата ON

Используется System.Text.Jsonформатировщики ON по умолчаниюJS. Чтобы использовать Newtonsoft.Jsonсредства форматирования на основе, установите Microsoft.AspNetCore.Mvc.NewtonsoftJson пакет NuGet и настройте его в Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .AddNewtonsoftJson();

В приведенном выше коде вызов AddNewtonsoftJson настраивает следующие функции веб-API, MVC и Razor Pages для использования Newtonsoft.Json:

Возможно, некоторые функции не будут оптимально работать с форматировщиками на основе System.Text.Json и будут требовать ссылки на форматировщики на основе Newtonsoft.Json. Продолжайте использовать Newtonsoft.Jsonсредства форматирования на основе, когда приложение:

  • Использует атрибут Newtonsoft.Json. Например, [JsonProperty] или [JsonIgnore].
  • Настраивает параметры сериализации.
  • Зависит от функций, предоставляемых Newtonsoft.Json.

Чтобы настроить функции для Newtonsoft.Jsonформатировщиков на основе, используйте SerializerSettingsследующую команду:

builder.Services.AddControllers()
    .AddNewtonsoftJson(options =>
    {
        options.SerializerSettings.ContractResolver = new DefaultContractResolver();
    });

Чтобы настроить параметры сериализации выходных данных для определенных действий, используйте JsonResult. Например:

[HttpGet]
public IActionResult GetNewtonsoftJson() =>
    new JsonResult(
        _todoItemStore.GetList(),
        new JsonSerializerSettings
        {
            ContractResolver = new DefaultContractResolver()
        });

Указание формата

Чтобы ограничить форматы ответа, примените фильтр [Produces]. Как и большинство фильтров, [Produces] можно применить к действию, контроллеру или глобальной области.

[ApiController]
[Route("api/[controller]")]
[Produces("application/json")]
public class TodoItemsController : ControllerBase

Предыдущий фильтр [Produces]:

  • Принудительно принуждает все действия контроллера возвращать JSответы в формате ON для POCOs (обычные старые объекты CLR) или ObjectResult их производных типов.
  • Возвращать JSответы в формате ON, даже если настроены другие модули форматирования, а клиент задает другой формат.

Дополнительные сведения см. в статье Фильтры в ASP.NET Core.

Специальные форматировщики

Встроенные модули форматирования реализуют некоторые специальные возможности. По умолчанию типы возвращаемых значений string форматируются как text/plain (text/html, если того требует заголовок Accept). Это поведение можно отключить, удалив StringOutputFormatter. Форматировщики удаляются в Program.cs. Действия, у которых типом возвращаемого объекта является модель, возвращают ответ 204 No Content при возврате значения null. Это поведение можно отключить, удалив HttpNoContentOutputFormatter. Приведенный ниже код удаляет StringOutputFormatter и HttpNoContentOutputFormatter.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers(options =>
{
    // using Microsoft.AspNetCore.Mvc.Formatters;
    options.OutputFormatters.RemoveType<StringOutputFormatter>();
    options.OutputFormatters.RemoveType<HttpNoContentOutputFormatter>();
});

StringOutputFormatterБез встроенных JSформатов форматирования string ON возвращают типы. Если встроенный JSмодуль форматирования ON удален, а xml-форматировщик доступен, возвращаемые типы форматов XML-форматирования string . В противном случае, string типы возвращаемого значения возвращают 406 Not Acceptable.

Без HttpNoContentOutputFormatter объекты со значением null форматируются с помощью настроенного модуля форматирования. Например:

  • Модуль JSформатирования ON возвращает ответ с текстом null.
  • Форматировщик XML возвращает пустой XML-элемент с атрибутом xsi:nil="true".

Сопоставления URL-адреса для формата ответа

Клиенты могут запрашивать определенный формат как часть URL-адреса, например:

  • В строке запроса или в части пути.
  • С использованием расширения файла конкретного формата, такого как XML или JSON.

Сопоставление из пути запроса должно быть указано в маршруте, используемом API. Например:

[ApiController]
[Route("api/[controller]")]
[FormatFilter]
public class TodoItemsController : ControllerBase
{
    private readonly TodoItemStore _todoItemStore;

    public TodoItemsController(TodoItemStore todoItemStore) =>
        _todoItemStore = todoItemStore;

    [HttpGet("{id:long}.{format?}")]
    public TodoItem? GetById(long id) =>
        _todoItemStore.GetById(id);

Предыдущий маршрут позволяет указать запрошенный формат с помощью дополнительного расширения файла. Атрибут [FormatFilter] проверяет наличие значения формата в RouteData и сопоставляет этот формат ответа с соответствующим форматировщиком при создании ответа.

Маршрут Форматировщик
/api/todoitems/5 Модуль форматирования вывода по умолчанию
/api/todoitems/5.json Модуль JSформатирования ON (если настроено)
/api/todoitems/5.xml Модуль форматирования XML (если настроен)

Полиморфная десериализация

Встроенные функции предоставляют ограниченный диапазон полиморфной сериализации, но совсем не поддерживают десериализацию. Для десериализации требуется настраиваемый преобразователь. Полный пример полиморфной десериализации см. в разделе "Полиморфная десериализация ".

Дополнительные ресурсы

Приложение MVC ASP.NET Core поддерживает форматирование данных ответа. Данные ответа могут возвращаться в определенных форматах или в формате, запрошенном клиентом.

Просмотреть или скачать образец кода (описание загрузки)

Результаты действий для конкретного формата

Некоторые типы результатов действий характерны для определенного формата, например JsonResult и ContentResult. Действия могут возвращать результаты в определенном формате независимо от настроек клиента. Например, возвращая возвращаемые JsonResultJSданные в формате ON. При возврате ContentResult или строки возвращаются строковые данные в формате обычного текста.

Действие не должно возвращать данные конкретного типа. ASP.NET Core поддерживает любое возвращаемое значение объекта. Результаты действий, возвращающих объекты, которые не IActionResult являются типами, сериализуются с помощью соответствующей IOutputFormatter реализации. Дополнительные сведения см. в разделе "Типы возвращаемых действий контроллера" в веб-API ASP.NET Core.

Встроенный вспомогательный метод Ok возвращает JSданные в формате ON:

// GET: api/authors
[HttpGet]
public ActionResult Get()
{
    return Ok(_authors.List());
}

Скачанный пример возвращает список авторов. Использование средств разработчика браузера F12 или http-repl с предыдущим кодом:

  • Отобразится заголовок ответа, содержащий content-type:application/json; charset=utf-8.
  • Отобразятся заголовки запросов. Например, заголовок Accept. Приведенный выше код игнорирует заголовок Accept.

Чтобы возвратить данные в формате обычного текста, используйте ContentResult и вспомогательный метод Content:

// GET api/authors/about
[HttpGet("About")]
public ContentResult About()
{
    return Content("An API listing authors of docs.asp.net.");
}

В приведенном выше коде возвращаемым Content-Type является text/plain. При возврате строки возвращается Content-Type со значением text/plain:

// GET api/authors/version
[HttpGet("version")]
public string Version()
{
    return "Version 1.0.0";
}

Для действий с несколькими возвращаемыми типами возвращается значение IActionResult. Например, возвращаются различные коды состояния HTTP на основе результатов выполненных операций.

Согласование содержимого

Согласование содержимого происходит, когда клиент задает заголовок Accept. Формат по умолчанию, используемый ASP.NET Core, имеет значение JSON. Согласование содержимого:

  • реализуется с помощью ObjectResult;
  • встроено в результаты действия с определенным кодом состояния, возвращаемые из вспомогательных методов; вспомогательные методы результатов действия основаны на ObjectResult;

при возврате типа модели возвращаемым типом является ObjectResult.

Следующий метод действия использует вспомогательные методы Ok и NotFound:

// GET: api/authors/search?namelike=th
[HttpGet("Search")]
public IActionResult Search(string namelike)
{
    var result = _authors.GetByNameSubstring(namelike);
    if (!result.Any())
    {
        return NotFound(namelike);
    }
    return Ok(result);
}

По умолчанию ASP.NET Core поддерживает типы мультимедиа application/json, text/json и text/plain. Такие средства, как Fiddler или http-repl , могут задать Accept заголовок запроса, чтобы указать формат возврата. Если заголовок Accept содержит тип, который поддерживается сервером, возвращается этот тип. Сведения о добавлении дополнительных форматировщиков приведены в следующем разделе.

Действия контроллера могут возвращать POCO (простые объекты CLR). При возвращении POCO среда выполнения автоматически создает ObjectResult, который генерирует оболочку объекта. Клиент получает отформатированный сериализованный объект. Если возвращаемый объект имеет значение null, возвращается ответ 204 No Content.

Возвращение типа объекта:

// GET api/authors/RickAndMSFT
[HttpGet("{alias}")]
public Author Get(string alias)
{
    return _authors.GetByAlias(alias);
}

В приведенном выше коде запрос допустимого псевдонима автора получает ответ 200 OK с данными об авторе. Запрос недопустимого псевдонима возвращает ответ 204 No Content.

Заголовок Accept

Согласование содержимого выполняется только при наличии в запросе заголовка Accept. Если запрос содержит заголовок Accept, ASP.NET Core:

  • перечисляет типы мультимедиа в заголовке Accept в порядке предпочтения;
  • пытается найти форматировщик, который может создать ответ в одном из указанных форматов.

Если форматировщик, который может удовлетворить запрос клиента, не найден, ASP.NET Core:

  • Возвращает значение 406 Not Acceptable , если MvcOptions.ReturnHttpNotAcceptable задано значение true, или -
  • пытается найти первый форматировщик, который может создать ответ.

Если форматировщик, обеспечивающий требуемый формат, не настроен, используется первый форматировщик, способный отформатировать данный объект. Если в запросе не отображается заголовок Accept:

  • Для сериализации ответа используется первый форматировщик, который может работать с объектом.
  • Согласование не выполняется. Сервер определяет возвращаемый формат.

Если заголовок Accept содержит */*, он игнорируется, если только RespectBrowserAcceptHeader не имеет значение true в MvcOptions.

Браузеры и согласование содержимого

В отличие от обычных клиентов API, веб-браузеры предоставляют заголовки Accept. Веб-браузеры указывают множество форматов, включая дикие карта. Если платформа обнаруживает, что запрос поступает из браузера, по умолчанию выполняется следующее:

  • Заголовок Accept игнорируется.
  • Содержимое возвращается в JSON, если иное не настроено.

Этот подход обеспечивает более согласованный интерфейс в браузерах при использовании API.

Чтобы настроить приложение для учета заголовков Accept в браузере, установите для параметра RespectBrowserAcceptHeader значение true:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options =>
    {
        options.RespectBrowserAcceptHeader = true; // false by default
    });
}

Настройка форматировщиков

В приложениях, которым требуется поддержка дополнительных форматов, можно добавлять соответствующие пакеты NuGet и настраивать поддержку. Существуют отдельные модули форматирования для ввода и вывода. Форматировщики ввода используются привязкой модели. Форматировщики вывода используются для форматирования ответов. Сведения о создании пользовательского форматировщика см. в статье Пользовательские модули форматирования для веб-API в ASP.NET Core.

Добавление поддержки формата XML

Форматировщики XML, реализованные с помощью XmlSerializer, можно настроить путем вызова AddXmlSerializerFormatters:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .AddXmlSerializerFormatters();
}

Приведенный выше код сериализует результаты с помощью XmlSerializer.

При использовании приведенного выше кода методы контроллера возвращают соответствующий формат на основе заголовка Accept запроса.

Настройка System.Text.Json баз данных форматирования

Функции для System.Text.Json баз данных форматирования можно настроить с помощью Microsoft.AspNetCore.Mvc.JsonOptions.JsonSerializerOptions. Форматирование по умолчанию — верблюдьи Регистр. Следующий выделенный код задает форматирование PascalCase:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .AddJsonOptions(options =>
            options.JsonSerializerOptions.PropertyNamingPolicy = null);
}

Для создания ProblemDetails ответа вызывается ControllerBase.Problem следующий метод действия:

[HttpGet("error")]
public IActionResult GetError()
{
    return Problem("Something went wrong!");
}

Приведенный выше код:

  • https://localhost:5001/WeatherForecast/temperature возвращает PascalCase.
  • https://localhost:5001/WeatherForecast/error возвращает верблюдьи Регистр. Ответ на ошибку всегда верблюдю Регистр, даже если приложение задает формат PascalCase. ProblemDetailsследует RFC 7807, который указывает нижний регистр

Следующий код задает PascalCase и добавляет пользовательский преобразователь:

services.AddControllers().AddJsonOptions(options =>
{
    // Use the default property (Pascal) casing.
    options.JsonSerializerOptions.PropertyNamingPolicy = null;

    // Configure a custom converter.
    options.JsonSerializerOptions.Converters.Add(new MyCustomJsonConverter());
});

Параметры сериализации выходных данных для отдельных действий можно настроить с помощью JsonResult. Например:

public IActionResult Get()
{
    return Json(model, new JsonSerializerOptions
    {
        WriteIndented = true,
    });
}

Добавление поддержки формата ON на основе JSNewtonsoft.Json

Параметры форматирования ON по умолчанию JSоснованы на System.Text.Json. Newtonsoft.Json Поддержка баз данных форматирования и функций доступна путем установки Microsoft.AspNetCore.Mvc.NewtonsoftJson пакета NuGet и его настройки.Startup.ConfigureServices

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .AddNewtonsoftJson();
}

В приведенном выше коде вызов AddNewtonsoftJson настраивает следующие функции веб-API, MVC и Razor Pages для использования Newtonsoft.Json:

Возможно, некоторые функции не будут оптимально работать с форматировщиками на основе System.Text.Json и будут требовать ссылки на форматировщики на основе Newtonsoft.Json. Продолжайте использовать Newtonsoft.Jsonсредства форматирования на основе, когда приложение:

  • Использует атрибут Newtonsoft.Json. Например, [JsonProperty] или [JsonIgnore].
  • Настраивает параметры сериализации.
  • Зависит от функций, предоставляемых Newtonsoft.Json.

Функции для форматировщиков на основе Newtonsoft.Json можно настроить с помощью Microsoft.AspNetCore.Mvc.MvcNewtonsoftJsonOptions.SerializerSettings:

services.AddControllers().AddNewtonsoftJson(options =>
{
    // Use the default property (Pascal) casing
    options.SerializerSettings.ContractResolver = new DefaultContractResolver();

    // Configure a custom converter
    options.SerializerSettings.Converters.Add(new MyCustomJsonConverter());
});

Параметры сериализации выходных данных для отдельных действий можно настроить с помощью JsonResult. Например:

public IActionResult Get()
{
    return Json(model, new JsonSerializerSettings
    {
        Formatting = Formatting.Indented,
    });
}

Указание формата

Чтобы ограничить форматы ответа, примените фильтр [Produces]. Как и большинство фильтров, [Produces] можно применить к действию, контроллеру или глобальной области.

[ApiController]
[Route("[controller]")]
[Produces("application/json")]
public class WeatherForecastController : ControllerBase
{

Предыдущий фильтр [Produces]:

  • Принудительно принуждает все действия контроллера возвращать JSответы в формате ON для POCOs (обычные старые объекты CLR) или ObjectResult их производных типов.
  • Если настроены другие методы форматирования, а клиент задает другой формат, JSвозвращается ON.

Дополнительные сведения см. в статье Фильтры в ASP.NET Core.

Специальные форматировщики

Встроенные модули форматирования реализуют некоторые специальные возможности. По умолчанию типы возвращаемых значений string форматируются как text/plain (text/html, если того требует заголовок Accept). Это поведение можно отключить, удалив StringOutputFormatter. Форматировщики удаляются в методе ConfigureServices. Действия, у которых типом возвращаемого объекта является модель, возвращают ответ 204 No Content при возврате значения null. Это поведение можно отключить, удалив HttpNoContentOutputFormatter. Приведенный ниже код удаляет StringOutputFormatter и HttpNoContentOutputFormatter.

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options =>
    {
        // requires using Microsoft.AspNetCore.Mvc.Formatters;
        options.OutputFormatters.RemoveType<StringOutputFormatter>();
        options.OutputFormatters.RemoveType<HttpNoContentOutputFormatter>();
    });
}

StringOutputFormatterБез встроенных JSформатов форматирования string ON возвращают типы. Если встроенный JSмодуль форматирования ON удален, а xml-форматировщик доступен, возвращаемые типы форматов XML-форматирования string . В противном случае, string типы возвращаемого значения возвращают 406 Not Acceptable.

Без HttpNoContentOutputFormatter объекты со значением null форматируются с помощью настроенного модуля форматирования. Например:

  • Модуль JSформатирования ON возвращает ответ с текстом null.
  • Форматировщик XML возвращает пустой XML-элемент с атрибутом xsi:nil="true".

Сопоставления URL-адреса для формата ответа

Клиенты могут запрашивать определенный формат как часть URL-адреса, например:

  • В строке запроса или в части пути.
  • С использованием расширения файла конкретного формата, такого как XML или JSON.

Сопоставление из пути запроса должно быть указано в маршруте, используемом API. Например:

[Route("api/[controller]")]
[ApiController]
[FormatFilter]
public class ProductsController : ControllerBase
{
    [HttpGet("{id}.{format?}")]
    public Product Get(int id)
    {

Этот маршрут позволяет задать запрошенный формат в качестве дополнительного расширения файла. Атрибут [FormatFilter] проверяет наличие значения формата в RouteData и сопоставляет этот формат ответа с соответствующим форматировщиком при создании ответа.

Маршрут Форматировщик
/api/products/5 Модуль форматирования вывода по умолчанию
/api/products/5.json Модуль JSформатирования ON (если настроено)
/api/products/5.xml Модуль форматирования XML (если настроен)

ASP.NET Core MVC поддерживает форматирование данных ответа, используя указанные форматы или в ответ на запрос клиента.

Результаты действий для конкретного формата

Некоторые типы результатов действий характерны для определенного формата, например JsonResult и ContentResult. Действия могут возвращать результаты, которые всегда используют указанный формат, игнорируя запрос клиента для другого формата. Например, возврат возвращаемых JsonResultJSданных в формате ON и возврат ContentResult возвращает данные строки с форматом обычного текста.

Действие не должно возвращать данные конкретного типа. ASP.NET Core поддерживает любое возвращаемое значение объекта. Результаты действий, возвращающих объекты, которые не IActionResult являются типами, сериализуются с помощью соответствующей IOutputFormatter реализации. Дополнительные сведения см. в разделе "Типы возвращаемых действий контроллера" в веб-API ASP.NET Core.

По умолчанию встроенный вспомогательный метод ControllerBase.Ok возвращает JSданные в формате ON:

[HttpGet]
public IActionResult Get()
    => Ok(_todoItemStore.GetList());

Пример кода возвращает список элементов todo. С помощью средств разработчика браузера F12 или http-repl с предыдущим кодом отображается следующее:

  • Заголовок ответа, содержащий тип контента:application/json; charset=utf-8.
  • Заголовки запроса. Например, заголовок Accept. Приведенный выше код игнорирует заголовок Accept.

Чтобы возвратить данные в формате обычного текста, используйте ContentResult и вспомогательный метод Content:

[HttpGet("Version")]
public ContentResult GetVersion()
    => Content("v1.0.0");

В приведенном выше коде возвращаемым Content-Type является text/plain.

Для действий с несколькими возвращаемыми типами возвращается значение IActionResult. Например, при возврате различных кодов состояния HTTP в зависимости от результата операции.

Согласование содержимого

Согласование содержимого происходит, когда клиент задает заголовок Accept. Формат по умолчанию, используемый ASP.NET Core, имеет значение JSON. Согласование содержимого:

  • реализуется с помощью ObjectResult;
  • встроено в результаты действия с определенным кодом состояния, возвращаемые из вспомогательных методов; вспомогательные методы результатов действия основаны на ObjectResult;

при возврате типа модели возвращаемым типом является ObjectResult.

Следующий метод действия использует вспомогательные методы Ok и NotFound:

[HttpGet("{id:long}")]
public IActionResult GetById(long id)
{
    var todo = _todoItemStore.GetById(id);

    if (todo is null)
    {
        return NotFound();
    }

    return Ok(todo);
}

По умолчанию ASP.NET Core поддерживает следующие типы носителей:

  • application/json
  • text/json
  • text/plain

Такие средства, как Fiddler или http-repl , могут задать Accept заголовок запроса, чтобы указать формат возврата. Если заголовок Accept содержит тип, который поддерживается сервером, возвращается этот тип. Сведения о добавлении дополнительных форматировщиков приведены в следующем разделе.

Действия контроллера могут возвращать POCO (простые объекты CLR). При возвращении POCO среда выполнения автоматически создает ObjectResult, который генерирует оболочку объекта. Клиент получает отформатированный сериализованный объект. Если возвращаемый объект имеет значение null, возвращается ответ 204 No Content.

В следующем примере возвращается тип объекта:

[HttpGet("{id:long}")]
public TodoItem? GetById(long id)
    => _todoItemStore.GetById(id);

В приведенном выше коде запрос допустимого элемента todo возвращает 200 OK ответ. Запрос недопустимого элемента todo возвращает 204 No Content ответ.

Заголовок Accept

Согласование содержимого выполняется только при наличии в запросе заголовка Accept. Если запрос содержит заголовок Accept, ASP.NET Core:

  • перечисляет типы мультимедиа в заголовке Accept в порядке предпочтения;
  • пытается найти форматировщик, который может создать ответ в одном из указанных форматов.

Если форматировщик, который может удовлетворить запрос клиента, не найден, ASP.NET Core:

  • Возвращает значение 406 Not Acceptable , если MvcOptions.ReturnHttpNotAcceptable задано значение true, или -
  • пытается найти первый форматировщик, который может создать ответ.

Если форматировщик, обеспечивающий требуемый формат, не настроен, используется первый форматировщик, способный отформатировать данный объект. Если в запросе не отображается заголовок Accept:

  • Для сериализации ответа используется первый форматировщик, который может работать с объектом.
  • Согласование не выполняется. Сервер определяет возвращаемый формат.

Если заголовок Accept содержит */*, он игнорируется, если только RespectBrowserAcceptHeader не имеет значение true в MvcOptions.

Браузеры и согласование содержимого

В отличие от обычных клиентов API, веб-браузеры предоставляют заголовки Accept. Веб-браузеры указывают множество форматов, включая дикие карта. Если платформа обнаруживает, что запрос поступает из браузера, по умолчанию выполняется следующее:

  • Заголовок Accept игнорируется.
  • Содержимое возвращается в JSON, если иное не настроено.

Этот подход обеспечивает более согласованный интерфейс в браузерах при использовании API.

Чтобы настроить приложение для соблюдения заголовков браузера, задайте RespectBrowserAcceptHeader для свойства trueзначение :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers(options =>
{
    options.RespectBrowserAcceptHeader = true;
});

Настройка форматировщиков

Приложения, которые должны поддерживать дополнительные форматы, могут добавлять соответствующие пакеты NuGet и настраивать поддержку. Существуют отдельные модули форматирования для ввода и вывода. Форматировщики ввода используются привязкой модели. Форматировщики вывода используются для форматирования ответов. Сведения о создании пользовательского форматировщика см. в статье Пользовательские модули форматирования для веб-API в ASP.NET Core.

Добавление поддержки формата XML

Чтобы настроить xml-форматировщики, реализованные с помощью , XmlSerializerвызов:AddXmlSerializerFormatters

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .AddXmlSerializerFormatters();

При использовании приведенного выше кода методы контроллера возвращают соответствующий формат на основе заголовка Accept запроса.

Настройка System.Text.Jsonформатировщиков на основе

Чтобы настроить функции для System.Text.Jsonформатировщиков на основе, используйте Microsoft.AspNetCore.Mvc.JsonOptions.JsonSerializerOptions. Следующий выделенный код настраивает форматирование PascalCase вместо форматирования верблюдьего Регистра по умолчанию:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.PropertyNamingPolicy = null;
    });

Чтобы настроить параметры сериализации выходных данных для определенных действий, используйте JsonResult. Например:

[HttpGet]
public IActionResult Get() 
    => new JsonResult(
        _todoItemStore.GetList(),
        new JsonSerializerOptions { PropertyNamingPolicy = null });

Добавление Newtonsoft.Jsonподдержки JSформата ON

Используется System.Text.Jsonформатировщики ON по умолчаниюJS. Чтобы использовать Newtonsoft.Jsonсредства форматирования на основе, установите Microsoft.AspNetCore.Mvc.NewtonsoftJson пакет NuGet и настройте его в Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .AddNewtonsoftJson();

В приведенном выше коде вызов AddNewtonsoftJson настраивает следующие функции веб-API, MVC и Razor Pages для использования Newtonsoft.Json:

Возможно, некоторые функции не будут оптимально работать с форматировщиками на основе System.Text.Json и будут требовать ссылки на форматировщики на основе Newtonsoft.Json. Продолжайте использовать Newtonsoft.Jsonсредства форматирования на основе, когда приложение:

  • Использует атрибут Newtonsoft.Json. Например, [JsonProperty] или [JsonIgnore].
  • Настраивает параметры сериализации.
  • Зависит от функций, предоставляемых Newtonsoft.Json.

Чтобы настроить функции для Newtonsoft.Jsonформатировщиков на основе, используйте SerializerSettingsследующую команду:

builder.Services.AddControllers()
    .AddNewtonsoftJson(options =>
    {
        options.SerializerSettings.ContractResolver = new DefaultContractResolver();
    });

Чтобы настроить параметры сериализации выходных данных для определенных действий, используйте JsonResult. Например:

[HttpGet]
public IActionResult GetNewtonsoftJson()
    => new JsonResult(
        _todoItemStore.GetList(),
        new JsonSerializerSettings { ContractResolver = new DefaultContractResolver() });

Формат ProblemDetails и ValidationProblemDetails ответы

Для создания ProblemDetails ответа вызывается ControllerBase.Problem следующий метод действия:

[HttpGet("Error")]
public IActionResult GetError()
    => Problem("Something went wrong.");

ProblemDetails Ответ всегда верблюдю Регистр, даже если приложение задает формат PascalCase. ProblemDetailsследует RFC 7807, который задает нижний регистр.

[ApiController] Если атрибут применяется к классу контроллера, контроллер создает ValidationProblemDetails ответ при сбое проверки модели. Этот ответ содержит словарь, который использует имена свойств модели в качестве ключей ошибок без изменений. Например, следующая модель включает одно свойство, требующее проверки:

public class SampleModel
{
    [Range(1, 10)]
    public int Value { get; set; }
}

По умолчанию ValidationProblemDetails ответ, возвращаемый, если Value свойство недопустимо, использует ключ Valueошибки, как показано в следующем примере:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "00-00000000000000000000000000000000-000000000000000-00",
  "errors": {
    "Value": [
      "The field Value must be between 1 and 10."
    ]
  }
}

Чтобы отформатировать имена свойств, используемые в качестве ключей IMetadataDetailsProvider ошибок, добавьте реализацию в коллекцию MvcOptions.ModelMetadataDetailsProviders . В следующем примере добавляется System.Text.Jsonреализация на основе, SystemTextJsonValidationMetadataProviderкоторая форматирует имена свойств как верблюдю по умолчанию:

builder.Services.AddControllers();

builder.Services.Configure<MvcOptions>(options =>
{
    options.ModelMetadataDetailsProviders.Add(
        new SystemTextJsonValidationMetadataProvider());
});

SystemTextJsonValidationMetadataProvider также принимает реализацию JsonNamingPolicy в конструкторе, которая задает настраиваемую политику именования для форматирования имен свойств.

Чтобы задать настраиваемое имя свойства в модели, используйте атрибут [JsonPropertyName] для свойства:

public class SampleModel
{
    [Range(1, 10)]
    [JsonPropertyName("sampleValue")]
    public int Value { get; set; }
}

Ответ, ValidationProblemDetails возвращаемый для предыдущей модели, если Value свойство недопустимо использует ключ sampleValueошибки, как показано в следующем примере:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "00-00000000000000000000000000000000-000000000000000-00",
  "errors": {
    "sampleValue": [
      "The field Value must be between 1 and 10."
    ]
  }
}

Чтобы отформатировать ValidationProblemDetails ответ, используйтеNewtonsoft.JsonNewtonsoftJsonValidationMetadataProvider:

builder.Services.AddControllers()
    .AddNewtonsoftJson();

builder.Services.Configure<MvcOptions>(options =>
{
    options.ModelMetadataDetailsProviders.Add(
        new NewtonsoftJsonValidationMetadataProvider());
});

По умолчанию форматирует имена свойств как верблюдю NewtonsoftJsonValidationMetadataProvider . NewtonsoftJsonValidationMetadataProvider также принимает реализацию NamingPolicy в конструкторе, которая задает настраиваемую политику именования для форматирования имен свойств. Чтобы задать пользовательское имя свойства в модели, используйте [JsonProperty] атрибут.

Указание формата

Чтобы ограничить форматы ответа, примените фильтр [Produces]. Как и большинство фильтров, [Produces] можно применить к действию, контроллеру или глобальной области.

[ApiController]
[Route("api/[controller]")]
[Produces("application/json")]
public class TodoItemsController : ControllerBase

Предыдущий фильтр [Produces]:

  • Принудительно принуждает все действия контроллера возвращать JSответы в формате ON для POCOs (обычные старые объекты CLR) или ObjectResult их производных типов.
  • Возвращать JSответы в формате ON, даже если настроены другие модули форматирования, а клиент задает другой формат.

Дополнительные сведения см. в статье Фильтры в ASP.NET Core.

Специальные форматировщики

Встроенные модули форматирования реализуют некоторые специальные возможности. По умолчанию типы возвращаемых значений string форматируются как text/plain (text/html, если того требует заголовок Accept). Это поведение можно отключить, удалив StringOutputFormatter. Форматировщики удаляются в Program.cs. Действия, у которых типом возвращаемого объекта является модель, возвращают ответ 204 No Content при возврате значения null. Это поведение можно отключить, удалив HttpNoContentOutputFormatter. Приведенный ниже код удаляет StringOutputFormatter и HttpNoContentOutputFormatter.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers(options =>
{
    // using Microsoft.AspNetCore.Mvc.Formatters;
    options.OutputFormatters.RemoveType<StringOutputFormatter>();
    options.OutputFormatters.RemoveType<HttpNoContentOutputFormatter>();
});

StringOutputFormatterБез встроенных JSформатов форматирования string ON возвращают типы. Если встроенный JSмодуль форматирования ON удален, а xml-форматировщик доступен, возвращаемые типы форматов XML-форматирования string . В противном случае, string типы возвращаемого значения возвращают 406 Not Acceptable.

Без HttpNoContentOutputFormatter объекты со значением null форматируются с помощью настроенного модуля форматирования. Например:

  • Модуль JSформатирования ON возвращает ответ с текстом null.
  • Форматировщик XML возвращает пустой XML-элемент с атрибутом xsi:nil="true".

Сопоставления URL-адреса для формата ответа

Клиенты могут запрашивать определенный формат как часть URL-адреса, например:

  • В строке запроса или в части пути.
  • С использованием расширения файла конкретного формата, такого как XML или JSON.

Сопоставление из пути запроса должно быть указано в маршруте, используемом API. Например:

[ApiController]
[Route("api/[controller]")]
[FormatFilter]
public class TodoItemsController : ControllerBase
{
    private readonly TodoItemStore _todoItemStore;

    public TodoItemsController(TodoItemStore todoItemStore)
        => _todoItemStore = todoItemStore;

    [HttpGet("{id:long}.{format?}")]
    public TodoItem? GetById(long id)
        => _todoItemStore.GetById(id);

Предыдущий маршрут позволяет указать запрошенный формат с помощью дополнительного расширения файла. Атрибут [FormatFilter] проверяет наличие значения формата в RouteData и сопоставляет этот формат ответа с соответствующим форматировщиком при создании ответа.

Маршрут Форматировщик
/api/todoitems/5 Модуль форматирования вывода по умолчанию
/api/todoitems/5.json Модуль JSформатирования ON (если настроено)
/api/todoitems/5.xml Модуль форматирования XML (если настроен)

Полиморфная десериализация

Встроенные функции предоставляют ограниченный диапазон полиморфной сериализации, но совсем не поддерживают десериализацию. Для десериализации требуется настраиваемый преобразователь. Полный пример полиморфной десериализации см. в разделе "Полиморфная десериализация ".

Дополнительные ресурсы