Создание веб-API с помощью ASP.NET Core

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

Класс ControllerBase

Веб-API на основе контроллера состоит из одного или нескольких классов контроллеров, производных от ControllerBase. Шаблон проекта веб-API предоставляет начальный контроллер:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

Контроллеры веб-API обычно должны быть производными от ControllerBaseController. Controller является производным от ControllerBase и добавляет поддержку для представлений, обеспечивая обработку веб-страниц, а не запросов веб-API. Если тот же контроллер должен поддерживать представления и веб-API, наследуем от Controller.

Класс ControllerBase предоставляет множество свойств и методов, которые удобны для обработки HTTP-запросов. Например, CreatedAtAction возвращает код состояния 201.

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

    return CreatedAtAction(nameof(GetById), new { id = pet.Id }, pet);
}

В следующей таблице приведены примеры методов в ControllerBase.

Метод Примечания
BadRequest Возвращает код состояния 400.
NotFound Возвращает код состояния 404.
PhysicalFile Возвращает файл.
TryUpdateModelAsync Вызывает привязку модели.
TryValidateModel Вызывает проверку модели.

Список всех доступных методов и свойств см. здесь: ControllerBase.

Атрибуты

Пространство имен Microsoft.AspNetCore.Mvc предоставляет атрибуты, которые можно использовать для настройки поведения контроллеров и методов действия веб-API. В следующем примере атрибуты используются для указания поддерживаемой команды действия HTTP и всех известных кодов состояния HTTP, которые могут быть возвращены:

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

    return CreatedAtAction(nameof(GetById), new { id = pet.Id }, pet);
}

Вот еще примеры доступных атрибутов.

Атрибут Примечания
[Route] Определяет шаблон URL-адреса для контроллера или действия.
[Bind] Задает префикс и свойства, которые добавляются для привязки модели.
[HttpGet] Определяет действие, которое поддерживает команду действия HTTP GET.
[Consumes] Указывает типы данных, которые принимает действие.
[Produces] Указывает типы данных, которые возвращает действие.

Список доступных атрибутов см. в пространстве имен Microsoft.AspNetCore.Mvc.

Атрибут ApiController

Атрибут [ApiController] можно применить к классу контроллера для включения следующих специализированных схем поведения API:

Атрибут в определенных контроллерах

Атрибут [ApiController] может применяться к определенным контроллерам, как показано в следующем примере из шаблона проекта:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

Атрибут в нескольких контроллерах

Один из подходов к использованию атрибута на более чем одном контроллере заключается в создании пользовательского базового класса контроллера, аннотированного атрибутом [ApiController]. В следующем примере демонстрируется пользовательский базовый класс и производный от него контроллер:

[ApiController]
public class MyControllerBase : ControllerBase
{
}
[Produces(MediaTypeNames.Application.Json)]
[Route("[controller]")]
public class PetsController : MyControllerBase

Атрибут в сборке

Атрибут [ApiController] можно применить к сборке. При применении атрибута [ApiController] к сборке все контроллеры в сборке применяют [ApiController] атрибут. Его нельзя отменить для отдельных контроллеров. Примените атрибут уровня сборки к файлу Program.cs :

using Microsoft.AspNetCore.Mvc;
[assembly: ApiController]

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Обязательная маршрутизация атрибутов

Атрибут [ApiController] требует обязательной маршрутизации атрибутов. Пример:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

Действия недоступны через обычные маршруты, определенные илиUseEndpointsUseMvcUseMvcWithDefaultRoute.

Автоматические отклики HTTP 400

Благодаря атрибуту [ApiController] ошибки проверки модели автоматически активируют отклик HTTP 400. В результате следующий код ненужен в методе действия:

if (!ModelState.IsValid)
{
    return BadRequest(ModelState);
}

Для выполнения предыдущей проверки ASP.NET Core MVC использует фильтр действий ModelStateInvalidFilter.

Отклик BadRequest по умолчанию

Следующий текст ответа является примером сериализованного типа:

{
  "": [
    "A non-empty request body is required."
  ]
}

Тип ответа HTTP 400 по умолчанию : ValidationProblemDetails. Следующий текст ответа является примером сериализованного типа:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "|7fb5e16a-4c8f23bbfc974667.",
  "errors": {
    "": [
      "A non-empty request body is required."
    ]
  }
}

Тип ValidationProblemDetails:

  • предоставляет распознаваемый компьютером формат для указания ошибок в откликах веб-API;
  • соответствует спецификации RFC 7807.

Чтобы обеспечить согласованность автоматических и настраиваемых ответов, вызовите метод ValidationProblem, а не BadRequest. ValidationProblem возвращает объект ValidationProblemDetails, а также автоматический ответ.

Запись в журнал автоматических откликов HTTP 400

Чтобы регистрировать автоматические 400 ответов, задайте свойство делегата InvalidModelStateResponseFactory для выполнения пользовательской обработки. По умолчанию InvalidModelStateResponseFactory используется ProblemDetailsFactory для создания экземпляра ValidationProblemDetails.

В следующем примере показано, как получить экземпляр для регистрации сведений ILogger<TCategoryName> об автоматическом ответе 400:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
      // To preserve the default behavior, capture the original delegate to call later.
        var builtInFactory = options.InvalidModelStateResponseFactory;

        options.InvalidModelStateResponseFactory = context =>
        {
            var logger = context.HttpContext.RequestServices
                                .GetRequiredService<ILogger<Program>>();

            // Perform logging here.
            // ...

            // Invoke the default behavior, which produces a ValidationProblemDetails
            // response.
            // To produce a custom response, return a different implementation of 
            // IActionResult instead.
            return builtInFactory(context);
        };
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Отключение автоматической активации отклика HTTP 400

Чтобы отключить автоматическую активацию отклика HTTP 400, задайте свойству SuppressModelStateInvalidFilter значение true. Добавьте выделенный ниже код:

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Вывод параметров источника привязки

Атрибут источника привязки определяет расположение, в котором находится значение параметра действия. Существуют следующие атрибуты источника привязки.

Атрибут Источник привязки
[FromBody] Текст запроса
[FromForm] Данные формы в тексте запроса
[FromHeader] Заголовок запроса
[FromQuery] Параметры строки запроса для запроса
[FromRoute] Данные маршрута из текущего запроса
[FromServices] Служба запросов, внедренная в качестве параметра действия

Предупреждение

Не используйте [FromRoute], если значения могут содержать %2f (то есть /). Для %2f не будет применяться отмена экранирования /. Используйте [FromQuery], если значение может содержать %2f.

Без атрибута [ApiController] или атрибутов источника привязки, таких как [FromQuery], среда выполнения ASP.NET Core попытается использовать связыватель модели для составного объекта. Связыватель модели для составного объекта извлекает данные из поставщиков значений в определенном порядке.

В следующем примере атрибут [FromQuery] указывает, что значение параметра discontinuedOnly задано в строке запроса URL-адреса для запроса:

[HttpGet]
public ActionResult<List<Product>> Get(
    [FromQuery] bool discontinuedOnly = false)
{
    List<Product> products = null;

    if (discontinuedOnly)
    {
        products = _productsInMemoryStore.Where(p => p.IsDiscontinued).ToList();
    }
    else
    {
        products = _productsInMemoryStore;
    }

    return products;
}

Атрибут [ApiController] применяет правила зависимости к источникам данных по умолчанию для параметров действий. Эти правила избавляют от необходимости вручную определять источники привязки путем применения атрибутов к параметрам действий. Правила зависимости источника привязки работают следующим образом:

  • [FromBody] выводится для параметров сложного типа, не зарегистрированных в контейнере внедрения зависимостей. Исключением из правила зависимости [FromBody] является любой сложный встроенный тип со специальным значением, такой как IFormCollection и CancellationToken. Код определения источника привязки игнорирует эти особые типы.
  • [FromForm] выводится для параметров действия с типом IFormFile и IFormFileCollection. Он не выводится ни для каких простых или определяемых пользователем типов.
  • [FromRoute] выводится для любого имени параметра действия, соответствующего параметру в шаблоне маршрута. Если параметру действия соответствуют несколько маршрутов, любое значение маршрута рассматривается как [FromRoute].
  • [FromQuery] выводится для любых других параметров действия.

Заметки о выводе FromBody

[FromBody] не определен для простых типов, таких как string или int. Таким образом, атрибут [FromBody] должен использоваться для простых типов, когда требуются эти функции.

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

  • [FromBody] выводится для обеих параметров, так как они являются сложными типами.

    [HttpPost]
    public IActionResult Action1(Product product, Order order)
    
  • Атрибут [FromBody], заданный одному параметру, выводится для другого, так как это сложный тип.

    [HttpPost]
    public IActionResult Action2(Product product, [FromBody] Order order)
    
  • Атрибут [FromBody] выводится для обоих параметров.

    [HttpPost]
    public IActionResult Action3([FromBody] Product product, [FromBody] Order order)
    

Отключение правил зависимости

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

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Вывод многокомпонентных запросов и запросов данных форм

Атрибут [ApiController] применяет правило вывода для параметров действия типа IFormFile и IFormFileCollection. Тип multipart/form-data контента запроса выводится для этих типов.

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

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Сведения о проблемах для кодов состояния ошибки

MVC преобразует результат ошибки (результат с кодом состояния 400 или более поздней версии) в результат с ProblemDetails. Тип ProblemDetails основан на спецификации RFC 7807 и предоставляет считываемые компьютером сведения об ошибке в HTTP-ответе.

Рассмотрим следующий код в действии контроллера:

if (pet == null)
{
    return NotFound();
}

Метод NotFound создает код состояния HTTP 404 с текстом ProblemDetails. Пример:

{
  type: "https://tools.ietf.org/html/rfc7231#section-6.5.4",
  title: "Not Found",
  status: 404,
  traceId: "0HLHLV31KRN83:00000001"
}

Отключение ответа ProblemDetails

Автоматическое создание ProblemDetails кода состояния ошибки отключено, если SuppressMapClientErrors свойству trueприсвоено значение :

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Определение поддерживаемых типов содержимого запросов с помощью атрибута [Consumes]

По умолчанию действие поддерживает все доступные типы содержимого запросов. Например, если в приложении включена поддержка форматировщиков входных данных JSON и XML, действие будет поддерживать несколько типов содержимого, включая application/json и application/xml.

Атрибут [Consumes] позволяет выполнять действие для ограничения поддерживаемых типов содержимого запросов. Примените атрибут [Consumes] к действию или контроллеру, указав один или несколько типов содержимого:

[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)

В приведенном выше коде действие CreateProduct указывает тип содержимого application/xml. Запросы, направляемые в это действие, должны определять заголовок Content-Typeapplication/xml. Запросы, не определяющие заголовок Content-Typeapplication/xml, возвращают ответ 415 Unsupported Media Type (неподдерживаемый тип данных).

Атрибут [Consumes] также позволяет действию влиять на выбор с учетом типа содержимого входящего запроса, применяя ограничение типа. Рассмотрим следующий пример.

[ApiController]
[Route("api/[controller]")]
public class ConsumesController : ControllerBase
{
    [HttpPost]
    [Consumes("application/json")]
    public IActionResult PostJson(IEnumerable<int> values) =>
        Ok(new { Consumes = "application/json", Values = values });

    [HttpPost]
    [Consumes("application/x-www-form-urlencoded")]
    public IActionResult PostForm([FromForm] IEnumerable<int> values) =>
        Ok(new { Consumes = "application/x-www-form-urlencoded", Values = values });
}

В приведенном выше коде для ConsumesController включена поддержка обработки запросов, отправляемых на URL-адрес https://localhost:5001/api/Consumes. Оба действия контроллера (PostJson и PostForm) обрабатывают запросы POST с одним и тем же URL-адресом. Если в атрибуте [Consumes] не применяется ограничение типа, возникает исключение неоднозначного соответствия.

Атрибут [Consumes] применяется к обоим действиям. Действие PostJson обрабатывает запросы, отправленные с заголовком Content-Typeapplication/json. Действие PostForm обрабатывает запросы, отправленные с заголовком Content-Typeapplication/x-www-form-urlencoded.

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

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

Класс ControllerBase

Веб-API на основе контроллера состоит из одного или нескольких классов контроллеров, производных от ControllerBase. Шаблон проекта веб-API предоставляет начальный контроллер:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

Контроллеры веб-API обычно должны быть производными от ControllerBaseController. Controller является производным от ControllerBase и добавляет поддержку для представлений, обеспечивая обработку веб-страниц, а не запросов веб-API. Если тот же контроллер должен поддерживать представления и веб-API, наследуем от Controller.

Класс ControllerBase предоставляет множество свойств и методов, которые удобны для обработки HTTP-запросов. Например, CreatedAtAction возвращает код состояния 201.

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

    return CreatedAtAction(nameof(GetById), new { id = pet.Id }, pet);
}

В следующей таблице приведены примеры методов в ControllerBase.

Метод Примечания
BadRequest Возвращает код состояния 400.
NotFound Возвращает код состояния 404.
PhysicalFile Возвращает файл.
TryUpdateModelAsync Вызывает привязку модели.
TryValidateModel Вызывает проверку модели.

Список всех доступных методов и свойств см. здесь: ControllerBase.

Атрибуты

Пространство имен Microsoft.AspNetCore.Mvc предоставляет атрибуты, которые можно использовать для настройки поведения контроллеров и методов действия веб-API. В следующем примере атрибуты используются для указания поддерживаемой команды действия HTTP и всех известных кодов состояния HTTP, которые могут быть возвращены:

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

    return CreatedAtAction(nameof(GetById), new { id = pet.Id }, pet);
}

Вот еще примеры доступных атрибутов.

Атрибут Примечания
[Route] Определяет шаблон URL-адреса для контроллера или действия.
[Bind] Задает префикс и свойства, которые добавляются для привязки модели.
[HttpGet] Определяет действие, которое поддерживает команду действия HTTP GET.
[Consumes] Указывает типы данных, которые принимает действие.
[Produces] Указывает типы данных, которые возвращает действие.

Список доступных атрибутов см. в пространстве имен Microsoft.AspNetCore.Mvc.

Атрибут ApiController

Атрибут [ApiController] можно применить к классу контроллера для включения следующих специализированных схем поведения API:

Атрибут в определенных контроллерах

Атрибут [ApiController] может применяться к определенным контроллерам, как показано в следующем примере из шаблона проекта:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

Атрибут в нескольких контроллерах

Один из подходов к использованию атрибута на более чем одном контроллере заключается в создании пользовательского базового класса контроллера, аннотированного атрибутом [ApiController]. В следующем примере демонстрируется пользовательский базовый класс и производный от него контроллер:

[ApiController]
public class MyControllerBase : ControllerBase
{
}
[Produces(MediaTypeNames.Application.Json)]
[Route("[controller]")]
public class PetsController : MyControllerBase

Атрибут в сборке

Атрибут [ApiController] можно применить к сборке. При применении атрибута [ApiController] к сборке все контроллеры в сборке [ApiController] применяют атрибут. Его нельзя отменить для отдельных контроллеров. Примените атрибут уровня сборки к файлу Program.cs :

using Microsoft.AspNetCore.Mvc;
[assembly: ApiController]

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Обязательная маршрутизация атрибутов

Атрибут [ApiController] требует обязательной маршрутизации атрибутов. Пример:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

Действия недоступны через обычные маршруты, UseMvcопределенные UseEndpointsили UseMvcWithDefaultRoute.

Автоматические отклики HTTP 400

Благодаря атрибуту [ApiController] ошибки проверки модели автоматически активируют отклик HTTP 400. В результате следующий код ненужен в методе действия:

if (!ModelState.IsValid)
{
    return BadRequest(ModelState);
}

Для выполнения предыдущей проверки ASP.NET Core MVC использует фильтр действий ModelStateInvalidFilter.

Отклик BadRequest по умолчанию

Следующий текст запроса является примером сериализованного типа:

{
  "": [
    "A non-empty request body is required."
  ]
}

Тип ответа http 400 по умолчанию — ValidationProblemDetails. Следующий текст запроса является примером сериализованного типа:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "|7fb5e16a-4c8f23bbfc974667.",
  "errors": {
    "": [
      "A non-empty request body is required."
    ]
  }
}

Тип ValidationProblemDetails:

  • предоставляет распознаваемый компьютером формат для указания ошибок в откликах веб-API;
  • соответствует спецификации RFC 7807.

Чтобы обеспечить согласованность автоматических и настраиваемых ответов, вызовите метод ValidationProblem, а не BadRequest. ValidationProblem возвращает объект ValidationProblemDetails, а также автоматический ответ.

Запись в журнал автоматических откликов HTTP 400

Чтобы регистрировать автоматические 400 ответов, задайте свойство делегата InvalidModelStateResponseFactory для выполнения пользовательской обработки. По умолчанию InvalidModelStateResponseFactory используется ProblemDetailsFactory для создания экземпляра ValidationProblemDetails.

В следующем примере показано, как получить экземпляр для регистрации сведений ILogger<TCategoryName> об автоматическом ответе 400:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
      // To preserve the default behavior, capture the original delegate to call later.
        var builtInFactory = options.InvalidModelStateResponseFactory;

        options.InvalidModelStateResponseFactory = context =>
        {
            var logger = context.HttpContext.RequestServices
                                .GetRequiredService<ILogger<Program>>();

            // Perform logging here.
            // ...

            // Invoke the default behavior, which produces a ValidationProblemDetails
            // response.
            // To produce a custom response, return a different implementation of 
            // IActionResult instead.
            return builtInFactory(context);
        };
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Отключение автоматической активации отклика HTTP 400

Чтобы отключить автоматическую активацию отклика HTTP 400, задайте свойству SuppressModelStateInvalidFilter значение true. Добавьте выделенный ниже код:

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Вывод параметров источника привязки

Атрибут источника привязки определяет расположение, в котором находится значение параметра действия. Существуют следующие атрибуты источника привязки.

Атрибут Источник привязки
[FromBody] Текст запроса
[FromForm] Данные формы в тексте запроса
[FromHeader] Заголовок запроса
[FromQuery] Параметры строки запроса для запроса
[FromRoute] Данные маршрута из текущего запроса
[FromServices] Служба запросов, внедренная в качестве параметра действия

Предупреждение

Не используйте [FromRoute], если значения могут содержать %2f (то есть /). Для %2f не будет применяться отмена экранирования /. Используйте [FromQuery], если значение может содержать %2f.

Без атрибута [ApiController] или атрибутов источника привязки, таких как [FromQuery], среда выполнения ASP.NET Core попытается использовать связыватель модели для составного объекта. Связыватель модели для составного объекта извлекает данные из поставщиков значений в определенном порядке.

В следующем примере атрибут [FromQuery] указывает, что значение параметра discontinuedOnly задано в строке запроса URL-адреса для запроса:

[HttpGet]
public ActionResult<List<Product>> Get(
    [FromQuery] bool discontinuedOnly = false)
{
    List<Product> products = null;

    if (discontinuedOnly)
    {
        products = _productsInMemoryStore.Where(p => p.IsDiscontinued).ToList();
    }
    else
    {
        products = _productsInMemoryStore;
    }

    return products;
}

Атрибут [ApiController] применяет правила зависимости к источникам данных по умолчанию для параметров действий. Эти правила избавляют от необходимости вручную определять источники привязки путем применения атрибутов к параметрам действий. Правила зависимости источника привязки работают следующим образом:

  • [FromServices] выводится для параметров сложного типа, зарегистрированных в контейнере di.
  • [FromBody] выводится для параметров сложного типа, не зарегистрированных в контейнере di. Исключением из правила зависимости [FromBody] является любой сложный встроенный тип со специальным значением, такой как IFormCollection и CancellationToken. Код определения источника привязки игнорирует эти особые типы.
  • [FromForm] выводится для параметров действия с типом IFormFile и IFormFileCollection. Он не выводится ни для каких простых или определяемых пользователем типов.
  • [FromRoute] выводится для любого имени параметра действия, соответствующего параметру в шаблоне маршрута. Если параметру действия соответствуют несколько маршрутов, любое значение маршрута рассматривается как [FromRoute].
  • [FromQuery] выводится для любых других параметров действия.

Заметки о выводе FromBody

[FromBody] не определен для простых типов, таких как string или int. Таким образом, атрибут [FromBody] должен использоваться для простых типов, когда требуются эти функции.

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

  • [FromBody] выводится для обеих параметров, так как они являются сложными типами.

    [HttpPost]
    public IActionResult Action1(Product product, Order order)
    
  • Атрибут [FromBody], заданный одному параметру, выводится для другого, так как это сложный тип.

    [HttpPost]
    public IActionResult Action2(Product product, [FromBody] Order order)
    
  • Атрибут [FromBody] выводится для обоих параметров.

    [HttpPost]
    public IActionResult Action3([FromBody] Product product, [FromBody] Order order)
    

Заметки о выводе FromServices

[FromServices] Вывод может повлиять на приложение в редких случаях, если тип параметра зарегистрирован в контейнере внедрения зависимостей, а также должен быть привязан из другого источника, например. FromBody.

Чтобы отключить [FromServices] вывод для одного параметра действия, примените к параметру требуемый атрибут источника привязки. Например, примените [FromBody] атрибут к параметру действия, который должен быть привязан из текста запроса.

Чтобы отключить [FromServices] вывод глобально, задайте Microsoft.AspNetCore.Mvc.ApiBehaviorOptions.DisableImplicitFromServicesParameters для свойства trueзначение :

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
        options.DisableImplicitFromServicesParameters = true;
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Отключение правил зависимости

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

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
        options.DisableImplicitFromServicesParameters = true;
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Вывод многокомпонентных запросов и запросов данных форм

Атрибут [ApiController] применяет правило вывода для параметров действия типа IFormFile и IFormFileCollection. Тип multipart/form-data контента запроса выводится для этих типов.

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

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Сведения о проблемах для кодов состояния ошибки

MVC преобразует результат ошибки (результат с кодом состояния 400 или более поздней версии) в результат с ProblemDetails. Тип ProblemDetails основан на спецификации RFC 7807 и предоставляет считываемые компьютером сведения об ошибке в HTTP-ответе.

Рассмотрим следующий код в действии контроллера:

if (pet == null)
{
    return NotFound();
}

Метод NotFound создает код состояния HTTP 404 с текстом ProblemDetails. Пример:

{
  type: "https://tools.ietf.org/html/rfc7231#section-6.5.4",
  title: "Not Found",
  status: 404,
  traceId: "0HLHLV31KRN83:00000001"
}

Отключение ответа ProblemDetails

Отключить автоматическое создание ProblemDetails для кодов состояния ошибок можно, задав свойству SuppressMapClientErrors значение true. Добавьте следующий код:

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Определение поддерживаемых типов содержимого запросов с помощью атрибута [Consumes]

По умолчанию действие поддерживает все доступные типы содержимого запросов. Например, если в приложении включена поддержка форматировщиков входных данных JSON и XML, действие будет поддерживать несколько типов содержимого, включая application/json и application/xml.

Атрибут [Consumes] позволяет выполнять действие для ограничения поддерживаемых типов содержимого запросов. Примените атрибут [Consumes] к действию или контроллеру, указав один или несколько типов содержимого:

[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)

В приведенном выше коде действие CreateProduct указывает тип содержимого application/xml. Запросы, направляемые в это действие, должны определять заголовок Content-Typeapplication/xml. Запросы, не определяющие заголовок Content-Typeapplication/xml, возвращают ответ 415 Unsupported Media Type (неподдерживаемый тип данных).

Атрибут [Consumes] также позволяет действию влиять на выбор с учетом типа содержимого входящего запроса, применяя ограничение типа. Рассмотрим следующий пример.

[ApiController]
[Route("api/[controller]")]
public class ConsumesController : ControllerBase
{
    [HttpPost]
    [Consumes("application/json")]
    public IActionResult PostJson(IEnumerable<int> values) =>
        Ok(new { Consumes = "application/json", Values = values });

    [HttpPost]
    [Consumes("application/x-www-form-urlencoded")]
    public IActionResult PostForm([FromForm] IEnumerable<int> values) =>
        Ok(new { Consumes = "application/x-www-form-urlencoded", Values = values });
}

В приведенном выше коде для ConsumesController включена поддержка обработки запросов, отправляемых на URL-адрес https://localhost:5001/api/Consumes. Оба действия контроллера (PostJson и PostForm) обрабатывают запросы POST с одним и тем же URL-адресом. Если в атрибуте [Consumes] не применяется ограничение типа, возникает исключение неоднозначного соответствия.

Атрибут [Consumes] применяется к обоим действиям. Действие PostJson обрабатывает запросы, отправленные с заголовком Content-Typeapplication/json. Действие PostForm обрабатывает запросы, отправленные с заголовком Content-Typeapplication/x-www-form-urlencoded.

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

ASP.NET Core поддерживает создание служб RESTful, также известных как веб-API, с помощью C#. Для обработки запросов веб-API использует контроллеры. В веб-API контроллеры — это классы, производные от ControllerBase. В этой статье показано, как использовать контроллеры для обработки веб-запросов API.

Просмотреть или скачать образец кода. (Инструкция по скачиванию.)

Класс ControllerBase

Веб-API состоит из одного или нескольких классов контроллера, которые являются производными от ControllerBase. Шаблон проекта веб-API предоставляет начальный контроллер:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

Не создавайте контроллер веб-API путем наследования от класса Controller. Controller является производным от ControllerBase и добавляет поддержку для представлений, обеспечивая обработку веб-страниц, а не запросов веб-API. Существует одно исключение из этого правила: если вы планируете использовать один и тот же контроллер для представлений и веб-API, сделайте его производным от Controller.

Класс ControllerBase предоставляет множество свойств и методов, которые удобны для обработки HTTP-запросов. Например, ControllerBase.CreatedAtAction возвращает код состояния 201.

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

    return CreatedAtAction(nameof(GetById), new { id = pet.Id }, pet);
}

Вот еще примеры методов, предоставляющих ControllerBase.

Метод Примечания
BadRequest Возвращает код состояния 400.
NotFound Возвращает код состояния 404.
PhysicalFile Возвращает файл.
TryUpdateModelAsync Вызывает привязку модели.
TryValidateModel Вызывает проверку модели.

Список всех доступных методов и свойств см. здесь: ControllerBase.

Атрибуты

Пространство имен Microsoft.AspNetCore.Mvc предоставляет атрибуты, которые можно использовать для настройки поведения контроллеров и методов действия веб-API. В следующем примере атрибуты используются для указания поддерживаемой команды действия HTTP и всех известных кодов состояния HTTP, которые могут быть возвращены:

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

    return CreatedAtAction(nameof(GetById), new { id = pet.Id }, pet);
}

Вот еще примеры доступных атрибутов.

Атрибут Примечания
[Route] Определяет шаблон URL-адреса для контроллера или действия.
[Bind] Задает префикс и свойства, которые добавляются для привязки модели.
[HttpGet] Определяет действие, которое поддерживает команду действия HTTP GET.
[Consumes] Указывает типы данных, которые принимает действие.
[Produces] Указывает типы данных, которые возвращает действие.

Список доступных атрибутов см. в пространстве имен Microsoft.AspNetCore.Mvc.

Атрибут ApiController

Атрибут [ApiController] можно применить к классу контроллера для включения следующих специализированных схем поведения API:

Атрибут в определенных контроллерах

Атрибут [ApiController] может применяться к определенным контроллерам, как показано в следующем примере из шаблона проекта:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

Атрибут в нескольких контроллерах

Один из подходов к использованию атрибута на более чем одном контроллере заключается в создании пользовательского базового класса контроллера, аннотированного атрибутом [ApiController]. В следующем примере демонстрируется пользовательский базовый класс и производный от него контроллер:

[ApiController]
public class MyControllerBase : ControllerBase
{
}
[Produces(MediaTypeNames.Application.Json)]
[Route("[controller]")]
public class PetsController : MyControllerBase

Атрибут в сборке

Атрибут [ApiController] можно применить к сборке. Аннотирование этим способом применяет поведение веб-API ко всем контроллерам в сборке. Его нельзя отменить для отдельных контроллеров. Примените атрибут уровня сборки к объявлению пространства имен, окружающему класс Startup:

[assembly: ApiController]
namespace WebApiSample
{
    public class Startup
    {
        ...
    }
}

Обязательная маршрутизация атрибутов

Атрибут [ApiController] требует обязательной маршрутизации атрибутов. Пример:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

Действия недоступны через обычные маршруты, определяемые UseEndpoints, UseMvc или UseMvcWithDefaultRoute в Startup.Configure.

Автоматические отклики HTTP 400

Благодаря атрибуту [ApiController] ошибки проверки модели автоматически активируют отклик HTTP 400. В результате следующий код ненужен в методе действия:

if (!ModelState.IsValid)
{
    return BadRequest(ModelState);
}

Для выполнения предыдущей проверки ASP.NET Core MVC использует фильтр действий ModelStateInvalidFilter.

Отклик BadRequest по умолчанию

Следующий текст запроса является примером сериализованного типа:

{
  "": [
    "A non-empty request body is required."
  ]
}

Тип ответа HTTP 400 по умолчанию : ValidationProblemDetails. Следующий текст запроса является примером сериализованного типа:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "|7fb5e16a-4c8f23bbfc974667.",
  "errors": {
    "": [
      "A non-empty request body is required."
    ]
  }
}

Тип ValidationProblemDetails:

  • предоставляет распознаваемый компьютером формат для указания ошибок в откликах веб-API;
  • соответствует спецификации RFC 7807.

Чтобы обеспечить согласованность автоматических и настраиваемых ответов, вызовите метод ValidationProblem, а не BadRequest. ValidationProblem возвращает объект ValidationProblemDetails, а также автоматический ответ.

Запись в журнал автоматических откликов HTTP 400

Чтобы регистрировать автоматические 400 ответов, задайте свойство делегата InvalidModelStateResponseFactory для выполнения пользовательской обработки.Startup.ConfigureServices По умолчанию InvalidModelStateResponseFactory используется ProblemDetailsFactory для создания экземпляра ValidationProblemDetails.

В следующем примере показано, как получить экземпляр для регистрации сведений ILogger<TCategoryName> об автоматическом ответе 400:

services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        // To preserve the default behavior, capture the original delegate to call later.
        var builtInFactory = options.InvalidModelStateResponseFactory;

        options.InvalidModelStateResponseFactory = context =>
        {
            var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<Startup>>();

            // Perform logging here.
            // ...

            // Invoke the default behavior, which produces a ValidationProblemDetails response.
            // To produce a custom response, return a different implementation of IActionResult instead.
            return builtInFactory(context);
        };
    });

Отключение автоматической активации отклика HTTP 400

Чтобы отключить автоматическую активацию отклика HTTP 400, задайте свойству SuppressModelStateInvalidFilter значение true. Добавьте выделенный ниже код в Startup.ConfigureServices:

services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
        options.DisableImplicitFromServicesParameters = true;
    });

Вывод параметров источника привязки

Атрибут источника привязки определяет расположение, в котором находится значение параметра действия. Существуют следующие атрибуты источника привязки.

Атрибут Источник привязки
[FromBody] Текст запроса
[FromForm] Данные формы в тексте запроса
[FromHeader] Заголовок запроса
[FromQuery] Параметры строки запроса для запроса
[FromRoute] Данные маршрута из текущего запроса
[FromServices] Служба запросов, внедренная в качестве параметра действия

Предупреждение

Не используйте [FromRoute], если значения могут содержать %2f (то есть /). Для %2f не будет применяться отмена экранирования /. Используйте [FromQuery], если значение может содержать %2f.

Без атрибута [ApiController] или атрибутов источника привязки, таких как [FromQuery], среда выполнения ASP.NET Core попытается использовать связыватель модели для составного объекта. Связыватель модели для составного объекта извлекает данные из поставщиков значений в определенном порядке.

В следующем примере атрибут [FromQuery] указывает, что значение параметра discontinuedOnly задано в строке запроса URL-адреса для запроса:

[HttpGet]
public ActionResult<List<Product>> Get(
    [FromQuery] bool discontinuedOnly = false)
{
    List<Product> products = null;

    if (discontinuedOnly)
    {
        products = _productsInMemoryStore.Where(p => p.IsDiscontinued).ToList();
    }
    else
    {
        products = _productsInMemoryStore;
    }

    return products;
}

Атрибут [ApiController] применяет правила зависимости к источникам данных по умолчанию для параметров действий. Эти правила избавляют от необходимости вручную определять источники привязки путем применения атрибутов к параметрам действий. Правила зависимости источника привязки работают следующим образом:

  • [FromBody] выводится для параметров сложного типа. Исключением из правила зависимости [FromBody] является любой сложный встроенный тип со специальным значением, такой как IFormCollection и CancellationToken. Код определения источника привязки игнорирует эти особые типы.
  • [FromForm] выводится для параметров действия с типом IFormFile и IFormFileCollection. Он не выводится ни для каких простых или определяемых пользователем типов.
  • [FromRoute] выводится для любого имени параметра действия, соответствующего параметру в шаблоне маршрута. Если параметру действия соответствуют несколько маршрутов, любое значение маршрута рассматривается как [FromRoute].
  • [FromQuery] выводится для любых других параметров действия.

Заметки о выводе FromBody

[FromBody] не определен для простых типов, таких как string или int. Таким образом, атрибут [FromBody] должен использоваться для простых типов, когда требуются эти функции.

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

  • [FromBody] выводится для обеих параметров, так как они являются сложными типами.

    [HttpPost]
    public IActionResult Action1(Product product, Order order)
    
  • Атрибут [FromBody], заданный одному параметру, выводится для другого, так как это сложный тип.

    [HttpPost]
    public IActionResult Action2(Product product, [FromBody] Order order)
    
  • Атрибут [FromBody] выводится для обоих параметров.

    [HttpPost]
    public IActionResult Action3([FromBody] Product product, [FromBody] Order order)
    

Отключение правил зависимости

Чтобы отключить вывод источника привязки, задайте SuppressInferBindingSourcesForParameters значение true. Добавьте следующий код в Startup.ConfigureServices:

services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
        options.DisableImplicitFromServicesParameters = true;
    });

Вывод многокомпонентных запросов и запросов данных форм

Атрибут [ApiController] применяет правило вывода для параметров действия типа IFormFile и IFormFileCollection. Тип multipart/form-data контента запроса выводится для этих типов.

Чтобы отключить поведение по умолчанию, задайте свойству SuppressConsumesConstraintForFormFileParameters значение true в Startup.ConfigureServices:

services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
        options.DisableImplicitFromServicesParameters = true;
    });

Сведения о проблемах для кодов состояния ошибки

MVC преобразует результат ошибки (результат с кодом состояния 400 или более поздней версии) в результат с ProblemDetails. Тип ProblemDetails основан на спецификации RFC 7807 и предоставляет считываемые компьютером сведения об ошибке в HTTP-ответе.

Рассмотрим следующий код в действии контроллера:

if (pet == null)
{
    return NotFound();
}

Метод NotFound создает код состояния HTTP 404 с текстом ProblemDetails. Пример:

{
  type: "https://tools.ietf.org/html/rfc7231#section-6.5.4",
  title: "Not Found",
  status: 404,
  traceId: "0HLHLV31KRN83:00000001"
}

Отключение ответа ProblemDetails

Отключить автоматическое создание ProblemDetails для кодов состояния ошибок можно, задав свойству SuppressMapClientErrors значение true. Добавьте следующий код в Startup.ConfigureServices:

services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
        options.DisableImplicitFromServicesParameters = true;
    });

Определение поддерживаемых типов содержимого запросов с помощью атрибута [Consumes]

По умолчанию действие поддерживает все доступные типы содержимого запросов. Например, если в приложении включена поддержка форматировщиков входных данных JSON и XML, действие будет поддерживать несколько типов содержимого, включая application/json и application/xml.

Атрибут [Consumes] позволяет выполнять действие для ограничения поддерживаемых типов содержимого запросов. Примените атрибут [Consumes] к действию или контроллеру, указав один или несколько типов содержимого:

[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)

В приведенном выше коде действие CreateProduct указывает тип содержимого application/xml. Запросы, направляемые в это действие, должны определять заголовок Content-Typeapplication/xml. Запросы, не определяющие заголовок Content-Typeapplication/xml, возвращают ответ 415 Unsupported Media Type (неподдерживаемый тип данных).

Атрибут [Consumes] также позволяет действию влиять на выбор с учетом типа содержимого входящего запроса, применяя ограничение типа. Рассмотрим следующий пример.

[ApiController]
[Route("api/[controller]")]
public class ConsumesController : ControllerBase
{
    [HttpPost]
    [Consumes("application/json")]
    public IActionResult PostJson(IEnumerable<int> values) =>
        Ok(new { Consumes = "application/json", Values = values });

    [HttpPost]
    [Consumes("application/x-www-form-urlencoded")]
    public IActionResult PostForm([FromForm] IEnumerable<int> values) =>
        Ok(new { Consumes = "application/x-www-form-urlencoded", Values = values });
}

В приведенном выше коде для ConsumesController включена поддержка обработки запросов, отправляемых на URL-адрес https://localhost:5001/api/Consumes. Оба действия контроллера (PostJson и PostForm) обрабатывают запросы POST с одним и тем же URL-адресом. Если в атрибуте [Consumes] не применяется ограничение типа, возникает исключение неоднозначного соответствия.

Атрибут [Consumes] применяется к обоим действиям. Действие PostJson обрабатывает запросы, отправленные с заголовком Content-Typeapplication/json. Действие PostForm обрабатывает запросы, отправленные с заголовком Content-Typeapplication/x-www-form-urlencoded.

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

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase

Не создавайте контроллер веб-API путем наследования от класса Controller. Controller является производным от ControllerBase и добавляет поддержку для представлений, обеспечивая обработку веб-страниц, а не запросов веб-API. Существует одно исключение из этого правила: если вы планируете использовать один и тот же контроллер для представлений и веб-API, сделайте его производным от Controller. Класс ControllerBase предоставляет множество свойств и методов, которые удобны для обработки HTTP-запросов. Например, ControllerBase.CreatedAtAction возвращает код состояния 201.

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

    return CreatedAtAction(nameof(GetById), new { id = pet.Id }, pet);
}

Ниже приведены некоторые примеры методов, которые ControllerBase предоставляют:

Метод Примечания
BadRequest Возвращает код состояния 400.
NotFound Возвращает код состояния 404.
PhysicalFile Возвращает файл.
TryUpdateModelAsync Вызывает привязку модели.
TryValidateModel Вызывает проверку модели.

Список всех доступных методов и свойств см. здесь: ControllerBase.

Атрибуты

Пространство имен Microsoft.AspNetCore.Mvc предоставляет атрибуты, которые можно использовать для настройки поведения контроллеров и методов действия веб-API. В следующем примере атрибуты используются для указания поддерживаемой команды действия HTTP и всех известных кодов состояния HTTP, которые могут быть возвращены:

[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<Pet> Create(Pet pet)
{
    pet.Id = _petsInMemoryStore.Any() ? 
             _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
    _petsInMemoryStore.Add(pet);

    return CreatedAtAction(nameof(GetById), new { id = pet.Id }, pet);
}

Ниже приведены некоторые примеры доступных атрибутов:

Атрибут Примечания
[Route] Определяет шаблон URL-адреса для контроллера или действия.
[Bind] Задает префикс и свойства, которые добавляются для привязки модели.
[HttpGet] Определяет действие, которое поддерживает команду действия HTTP GET.
[Consumes] Указывает типы данных, которые принимает действие.
[Produces] Указывает типы данных, которые возвращает действие.

Список доступных атрибутов см. в пространстве имен Microsoft.AspNetCore.Mvc.

Атрибут ApiController

Атрибут [ApiController] можно применить к классу контроллера для включения следующих специализированных схем поведения API:

Атрибут в определенных контроллерах

Атрибут [ApiController] может применяться к определенным контроллерам, как показано в следующем примере из шаблона проекта:

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase

Атрибут в нескольких контроллерах

Один из подходов к использованию атрибута на более чем одном контроллере заключается в создании пользовательского базового класса контроллера, аннотированного атрибутом [ApiController]. В следующем примере демонстрируется пользовательский базовый класс и производный от него контроллер:

[ApiController]
public class MyControllerBase : ControllerBase
{
}
[Produces(MediaTypeNames.Application.Json)]
[Route("api/[controller]")]
public class PetsController : MyControllerBase

Атрибут в сборке

Если задана версия совместимости 2.2 или последующая, атрибут [ApiController] можно применить к сборке. Аннотирование этим способом применяет поведение веб-API ко всем контроллерам в сборке. Его нельзя отменить для отдельных контроллеров. Примените атрибут уровня сборки к объявлению пространства имен, окружающему класс Startup:

[assembly: ApiController]
namespace WebApiSample
{
    public class Startup
    {
        ...
    }
}

Обязательная маршрутизация атрибутов

Атрибут [ApiController] требует обязательной маршрутизации атрибутов. Пример:

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase

Действия недоступны через обычные маршруты, определяемые UseMvc или UseMvcWithDefaultRoute в Startup.Configure.

Автоматические отклики HTTP 400

Благодаря атрибуту [ApiController] ошибки проверки модели автоматически активируют отклик HTTP 400. В результате следующий код ненужен в методе действия:

if (!ModelState.IsValid)
{
    return BadRequest(ModelState);
}

Для выполнения предыдущей проверки ASP.NET Core MVC использует фильтр действий ModelStateInvalidFilter.

Отклик BadRequest по умолчанию

Если задана версия совместимости 2.1, для ответов HTTP 400 по умолчанию возвращается тип отклика SerializableError. Следующий текст запроса является примером сериализованного типа:

{
  "": [
    "A non-empty request body is required."
  ]
}

Если задана версия совместимости 2.2 или более поздние версии, для ответов HTTP 400 по умолчанию возвращается тип отклика ValidationProblemDetails. Следующий текст запроса является примером сериализованного типа:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "|7fb5e16a-4c8f23bbfc974667.",
  "errors": {
    "": [
      "A non-empty request body is required."
    ]
  }
}

Тип ValidationProblemDetails:

  • предоставляет распознаваемый компьютером формат для указания ошибок в откликах веб-API;
  • соответствует спецификации RFC 7807.

Чтобы обеспечить согласованность автоматических и настраиваемых ответов, вызовите метод ValidationProblem, а не BadRequest. ValidationProblem возвращает объект ValidationProblemDetails, а также автоматический ответ.

Запись в журнал автоматических откликов HTTP 400

См. описание проблемы записи в журнал автоматических ответов HTTP 400 для ошибок проверки модели (aspnet/AspNetCore.Docs#12157).

Отключение автоматической активации отклика HTTP 400

Чтобы отключить автоматическую активацию отклика HTTP 400, задайте свойству SuppressModelStateInvalidFilter значение true. Добавьте выделенный ниже код в Startup.ConfigureServices:

services.Configure<ApiBehaviorOptions>(options =>
{
    options.SuppressConsumesConstraintForFormFileParameters = true;
    options.SuppressInferBindingSourcesForParameters = true;
    options.SuppressModelStateInvalidFilter = true;
});

Вывод параметров источника привязки

Атрибут источника привязки определяет расположение, в котором находится значение параметра действия. Существуют следующие атрибуты источника привязки.

Атрибут Источник привязки
[FromBody] Текст запроса
[FromForm] Данные формы в тексте запроса
[FromHeader] Заголовок запроса
[FromQuery] Параметры строки запроса для запроса
[FromRoute] Данные маршрута из текущего запроса
[FromServices] Служба запросов, внедренная в качестве параметра действия

Предупреждение

Не используйте [FromRoute], если значения могут содержать %2f (то есть /). Для %2f не будет применяться отмена экранирования /. Используйте [FromQuery], если значение может содержать %2f. Без атрибута [ApiController] или атрибутов источника привязки, таких как [FromQuery], среда выполнения ASP.NET Core попытается использовать связыватель модели для составного объекта. Связыватель модели для составного объекта извлекает данные из поставщиков значений в определенном порядке.

В следующем примере атрибут [FromQuery] указывает, что значение параметра discontinuedOnly задано в строке запроса URL-адреса для запроса:

[HttpGet]
public ActionResult<List<Product>> Get(
    [FromQuery] bool discontinuedOnly = false)
{
    List<Product> products = null;

    if (discontinuedOnly)
    {
        products = _productsInMemoryStore.Where(p => p.IsDiscontinued).ToList();
    }
    else
    {
        products = _productsInMemoryStore;
    }

    return products;
}

Атрибут [ApiController] применяет правила зависимости к источникам данных по умолчанию для параметров действий. Эти правила избавляют от необходимости вручную определять источники привязки путем применения атрибутов к параметрам действий. Правила зависимости источника привязки работают следующим образом:

  • [FromBody] выводится для параметров сложного типа. Исключением из правила зависимости [FromBody] является любой сложный встроенный тип со специальным значением, такой как IFormCollection и CancellationToken. Код определения источника привязки игнорирует эти особые типы.
  • [FromForm] выводится для параметров действия с типом IFormFile и IFormFileCollection. Он не выводится ни для каких простых или определяемых пользователем типов.
  • [FromRoute] выводится для любого имени параметра действия, соответствующего параметру в шаблоне маршрута. Если параметру действия соответствуют несколько маршрутов, любое значение маршрута рассматривается как [FromRoute].
  • [FromQuery] выводится для любых других параметров действия.

Заметки о выводе FromBody

[FromBody] не определен для простых типов, таких как string или int. Таким образом, атрибут [FromBody] должен использоваться для простых типов, когда требуются эти функции.

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

  • [FromBody] выводится для обеих параметров, так как они являются сложными типами.

    [HttpPost]
    public IActionResult Action1(Product product, Order order)
    
  • Атрибут [FromBody], заданный одному параметру, выводится для другого, так как это сложный тип.

    [HttpPost]
    public IActionResult Action2(Product product, [FromBody] Order order)
    
  • Атрибут [FromBody] выводится для обоих параметров.

    [HttpPost]
    public IActionResult Action3([FromBody] Product product, [FromBody] Order order)
    

Примечание

В ASP.NET Core 2.1 параметры типа коллекции, такие как списки и массивы, ошибочно выводятся как [FromQuery]. Для этих параметров следует использовать атрибут [FromBody], если они должны быть привязаны из текста запроса. Это поведение, при котором параметры типа коллекции выводятся для привязки из текста по умолчанию, исправлено в версии ASP.NET Core, начиная с 2.2.

Отключение правил зависимости

Чтобы отключить вывод источника привязки, задайте SuppressInferBindingSourcesForParameters значение true. Добавьте следующий код в Startup.ConfigureServices:

services.Configure<ApiBehaviorOptions>(options =>
{
    options.SuppressConsumesConstraintForFormFileParameters = true;
    options.SuppressInferBindingSourcesForParameters = true;
    options.SuppressModelStateInvalidFilter = true;
});

Вывод многокомпонентных запросов и запросов данных форм

Атрибут [ApiController] применяет правило вывода для параметров действия типа IFormFile и IFormFileCollection. Тип multipart/form-data контента запроса выводится для этих типов. Чтобы отключить поведение по умолчанию, задайте свойству SuppressConsumesConstraintForFormFileParameters значение true в Startup.ConfigureServices:

services.Configure<ApiBehaviorOptions>(options =>
{
    options.SuppressConsumesConstraintForFormFileParameters = true;
    options.SuppressInferBindingSourcesForParameters = true;
    options.SuppressModelStateInvalidFilter = true;
});

Сведения о проблемах для кодов состояния ошибки

Если задана версия совместимости, начиная с 2.2, MVC преобразовывает код ошибки (код состояния 400 и далее) в результат с ProblemDetails. Тип ProblemDetails основан на спецификации RFC 7807 и предоставляет считываемые компьютером сведения об ошибке в HTTP-ответе. Рассмотрим следующий код в действии контроллера:

if (pet == null)
{
    return NotFound();
}

Метод NotFound создает код состояния HTTP 404 с текстом ProblemDetails. Пример:

{
  type: "https://tools.ietf.org/html/rfc7231#section-6.5.4",
  title: "Not Found",
  status: 404,
  traceId: "0HLHLV31KRN83:00000001"
}

Отключение ответа ProblemDetails

Отключить автоматическое создание ProblemDetails для кодов состояния ошибок можно, задав свойству SuppressMapClientErrors значение true. Добавьте следующий код в Startup.ConfigureServices:

Определение поддерживаемых типов содержимого запросов с помощью атрибута [Consumes]

По умолчанию действие поддерживает все доступные типы содержимого запросов. Например, если в приложении включена поддержка форматировщиков входных данных JSON и XML, действие будет поддерживать несколько типов содержимого, включая application/json и application/xml.

Атрибут [Consumes] позволяет выполнять действие для ограничения поддерживаемых типов содержимого запросов. Примените атрибут [Consumes] к действию или контроллеру, указав один или несколько типов содержимого:

[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)

В приведенном выше коде действие CreateProduct указывает тип содержимого application/xml. Запросы, направляемые в это действие, должны определять заголовок Content-Typeapplication/xml. Запросы, не определяющие заголовок Content-Typeapplication/xml, возвращают ответ 415 Unsupported Media Type (неподдерживаемый тип данных). Атрибут [Consumes] также позволяет действию влиять на выбор с учетом типа содержимого входящего запроса, применяя ограничение типа. Рассмотрим следующий пример.

[ApiController]
[Route("api/[controller]")]
public class ConsumesController : ControllerBase
{
    [HttpPost]
    [Consumes("application/json")]
    public IActionResult PostJson(IEnumerable<int> values) =>
        Ok(new { Consumes = "application/json", Values = values });

    [HttpPost]
    [Consumes("application/x-www-form-urlencoded")]
    public IActionResult PostForm([FromForm] IEnumerable<int> values) =>
        Ok(new { Consumes = "application/x-www-form-urlencoded", Values = values });
}

В приведенном выше коде для ConsumesController включена поддержка обработки запросов, отправляемых на URL-адрес https://localhost:5001/api/Consumes. Оба действия контроллера (PostJson и PostForm) обрабатывают запросы POST с одним и тем же URL-адресом. Если в атрибуте [Consumes] не применяется ограничение типа, возникает исключение неоднозначного соответствия. Атрибут [Consumes] применяется к обоим действиям. Действие PostJson обрабатывает запросы, отправленные с заголовком Content-Typeapplication/json. Действие PostForm обрабатывает запросы, отправленные с заголовком Content-Typeapplication/x-www-form-urlencoded.

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