Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
ASP.NET Core поддерживает создание веб-API с помощью контроллеров или использования минимальных API. В веб-API контроллеры — это классы, производные от ControllerBase. Контроллеры активируются и освобождаются при каждом запросе.
В этой статье показано, как использовать контроллеры для обработки веб-запросов API. Сведения о создании веб-API без контроллеров см. в руководстве по созданию минимального API с помощью ASP.NET Core.
Это важно
Начиная с версии ASP.NET Core 10, известные конечные точки API больше не перенаправляют на страницы входа при использовании cookie аутентификации. Вместо этого они возвращают коды состояния 401/403. Дополнительные сведения см. в статье о поведении проверки подлинности конечной точки API в ASP.NET Core.
Класс ControllerBase
Веб-API на основе контроллера состоит из одного или нескольких классов контроллера, которые являются производными от ControllerBase. Шаблон проекта веб-API предоставляет начальный контроллер:
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
Контроллеры веб-API обычно являются производными от ControllerBase, а не от Controller.
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.
| Method | Notes |
|---|---|
| BadRequest | Возвращает код состояния 400. |
| NotFound | Возвращает код состояния 404. |
| PhysicalFile | Возвращает файл. |
| TryUpdateModelAsync | Вызывает привязку модели. |
| TryValidateModel | Вызывает проверку модели. |
Список всех доступных методов и свойств см. здесь: ControllerBase.
Attributes
Пространство имен 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);
}
Вот еще примеры доступных атрибутов.
| Attribute | Notes |
|---|---|
[Route] |
Определяет шаблон URL-адреса для контроллера или действия. |
[Bind] |
Задает префикс и свойства, которые добавляются для привязки модели. |
[HttpGet] |
Определяет действие, которое поддерживает команду действия HTTP GET. |
[Consumes] |
Указывает типы данных, которые принимает действие. |
[Produces] |
Указывает типы данных, которые возвращает действие. |
Список доступных атрибутов см. в пространстве имен Microsoft.AspNetCore.Mvc.
Атрибут ApiController
Атрибут [ApiController] можно применить к классу контроллера для включения следующих специализированных схем поведения API:
- Обязательная маршрутизация атрибутов
- Автоматические отклики HTTP 400
- Вывод параметров источника привязки
- Интерпретация multipart/form-data запросов
- Сведения о проблемах для кодов состояния ошибки
Атрибут в определенных контроллерах
Атрибут [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
Действия недоступны через обычные маршруты, определяемые UseEndpoints, UseMvc или UseMvcWithDefaultRoute.
Автоматические отклики HTTP 400
Благодаря атрибуту [ApiController] ошибки проверки модели автоматически активируют отклик HTTP 400. В результате следующий код ненужен в методе действия:
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
Для выполнения предыдущей проверки ASP.NET Core MVC использует фильтр действий ModelStateInvalidFilter.
Отклик BadRequest по умолчанию
Для ответов 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();
Отключение автоматического ответа 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();
Определение параметров источника привязки
Атрибут источника привязки определяет расположение, в котором находится значение параметра действия. Существуют следующие атрибуты источника привязки.
| Attribute | Источник привязки |
|---|---|
[FromBody] |
Основное содержание запроса |
[FromForm] |
Данные формы в тексте запроса |
[FromHeader] |
Заголовок запроса |
[FromQuery] |
Параметр строки запроса |
[FromRoute] |
Данные маршрута из текущего запроса |
[FromServices] |
Служба запросов, внедренная в качестве параметра действия |
[AsParameters] |
Параметры метода |
Warning
Не используйте [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] к параметру не нужно. В следующем коде оба действия возвращают время:
[Route("[controller]")]
[ApiController]
public class MyController : ControllerBase
{
public ActionResult GetWithAttribute([FromServices] IDateTime dateTime)
=> Ok(dateTime.Now);
[Route("noAttribute")]
public ActionResult Get(IDateTime dateTime) => Ok(dateTime.Now);
}
В редких случаях автоматическое внедрение зависимостей может прервать работу приложения, если оно имеет во внедрении зависимостей тип, который также принимается в методах действий контроллеров API. Встроение типов одновременно во внедрение зависимостей и использование их в качестве аргументов в действиях контроллера API встречается нечасто.
Чтобы отключить вывод [FromServices] для одного параметра действия, примените к параметру требуемый атрибут источника привязки. Например, примените атрибут [FromBody] к параметру действия, который должен быть привязан из текста запроса.
Чтобы отключить вывод [FromServices] глобально, задайте для DisableImplicitFromServicesParameters значение true.
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddSingleton<IDateTime, SystemDateTime>();
builder.Services.Configure<ApiBehaviorOptions>(options =>
{
options.DisableImplicitFromServicesParameters = true;
});
var app = builder.Build();
app.MapControllers();
app.Run();
Типы проверяются при запуске приложения с помощью IServiceProviderIsService, чтобы определить, поступает ли аргумент в функции контроллера API из DI (внедрения зависимостей) или из других источников.
Механизм вывода источника привязки параметров действия контроллера API использует следующие правила:
- Ранее указанный
BindingInfo.BindingSourceникогда не перезаписывается. - В контейнер зависимостей назначается параметр сложного типа:
BindingSource.Services. - Сложному типу параметра, не зарегистрированному в контейнере DI, назначается
BindingSource.Body. - Параметру с именем, которое появляется как значение маршрута в любом шаблоне маршрута, присваивается
BindingSource.Path. - В качестве остальных параметров используется
BindingSource.Query.
Отключение правил вывода
Чтобы отключить определение источника привязки, установите для SuppressInferBindingSourcesForParameters значение 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();
Вывод многокомпонентных запросов и запросов данных форм
Атрибут [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.
Дополнительные ресурсы
- Просмотреть или скачать образец кода. (Инструкция по скачиванию.)
- Типы возвращаемых действий контроллера в веб-API ASP.NET Core
- Обработка ошибок в api ASP.NET Core
- Пользовательские форматировщики в веб-API ASP.NET Core
- Форматирование данных ответа в веб-API ASP.NET Core
- документация по веб-API ASP.NET Core с помощью Swagger / OpenAPI
- Маршрутизация на действия контроллера в ASP.NET Core
- Использование туннелирования портов Visual Studio для отладки веб-API
- Создание веб-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 обычно являются производными от ControllerBase, а не от Controller.
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.
| Method | Notes |
|---|---|
| BadRequest | Возвращает код состояния 400. |
| NotFound | Возвращает код состояния 404. |
| PhysicalFile | Возвращает файл. |
| TryUpdateModelAsync | Вызывает привязку модели. |
| TryValidateModel | Вызывает проверку модели. |
Список всех доступных методов и свойств см. здесь: ControllerBase.
Attributes
Пространство имен 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);
}
Вот еще примеры доступных атрибутов.
| Attribute | Notes |
|---|---|
[Route] |
Определяет шаблон URL-адреса для контроллера или действия. |
[Bind] |
Задает префикс и свойства, которые добавляются для привязки модели. |
[HttpGet] |
Определяет действие, которое поддерживает команду действия HTTP GET. |
[Consumes] |
Указывает типы данных, которые принимает действие. |
[Produces] |
Указывает типы данных, которые возвращает действие. |
Список доступных атрибутов см. в пространстве имен Microsoft.AspNetCore.Mvc.
Атрибут ApiController
Атрибут [ApiController] можно применить к классу контроллера для включения следующих специализированных схем поведения API:
- Обязательная маршрутизация атрибутов
- Автоматические отклики HTTP 400
- Вывод параметров источника привязки
- Интерпретация multipart/form-data запросов
- Сведения о проблемах для кодов состояния ошибки
Атрибут в определенных контроллерах
Атрибут [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
Действия недоступны через обычные маршруты, определяемые UseEndpoints, UseMvc или 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();
Отключение автоматического ответа 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();
Определение параметров источника привязки
Атрибут источника привязки определяет расположение, в котором находится значение параметра действия. Существуют следующие атрибуты источника привязки.
| Attribute | Источник привязки |
|---|---|
[FromBody] |
Основное содержание запроса |
[FromForm] |
Данные формы в тексте запроса |
[FromHeader] |
Заголовок запроса |
[FromQuery] |
Параметр строки запроса |
[FromRoute] |
Данные маршрута из текущего запроса |
[FromServices] |
Служба запросов, внедренная в качестве параметра действия |
Warning
Не используйте [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]выводится для параметров сложного типа, не зарегистрированных в контейнере 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)
Отключение правил вывода
Чтобы отключить определение источника привязки, установите для SuppressInferBindingSourcesForParameters значение 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();
Вывод многокомпонентных запросов и запросов данных форм
Атрибут [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.
Дополнительные ресурсы
- Просмотреть или скачать образец кода. (Инструкция по скачиванию.)
- Типы возвращаемых действий контроллера в веб-API ASP.NET Core
- Обработка ошибок в api ASP.NET Core
- Пользовательские форматтеры в ASP.NET Core Web API
- Форматирование данных ответа в веб-API ASP.NET Core
- документация по веб-API ASP.NET Core с помощью Swagger / OpenAPI
- Маршрутизация на действия контроллера в ASP.NET Core
- Использование туннелирования портов Visual Studio для отладки веб-API
- Создание веб-API с помощью ASP.NET Core
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.
| Method | Notes |
|---|---|
| BadRequest | Возвращает код состояния 400. |
| NotFound | Возвращает код состояния 404. |
| PhysicalFile | Возвращает файл. |
| TryUpdateModelAsync | Вызывает привязку модели. |
| TryValidateModel | Вызывает проверку модели. |
Список всех доступных методов и свойств см. здесь: ControllerBase.
Attributes
Пространство имен 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);
}
Вот еще примеры доступных атрибутов.
| Attribute | Notes |
|---|---|
[Route] |
Определяет шаблон URL-адреса для контроллера или действия. |
[Bind] |
Задает префикс и свойства, которые добавляются для привязки модели. |
[HttpGet] |
Определяет действие, которое поддерживает команду действия HTTP GET. |
[Consumes] |
Указывает типы данных, которые принимает действие. |
[Produces] |
Указывает типы данных, которые возвращает действие. |
Список доступных атрибутов см. в пространстве имен Microsoft.AspNetCore.Mvc.
Атрибут ApiController
Атрибут [ApiController] можно применить к классу контроллера для включения следующих специализированных схем поведения API:
- Обязательная маршрутизация атрибутов
- Автоматические отклики HTTP 400
- Вывод параметров источника привязки
- Интерпретация multipart/form-data запросов
- Сведения о проблемах для кодов состояния ошибки
Атрибут в определенных контроллерах
Атрибут [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);
};
});
Отключение автоматического ответа 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;
});
Определение параметров источника привязки
Атрибут источника привязки определяет расположение, в котором находится значение параметра действия. Существуют следующие атрибуты источника привязки.
| Attribute | Источник привязки |
|---|---|
[FromBody] |
Основное содержание запроса |
[FromForm] |
Данные формы в тексте запроса |
[FromHeader] |
Заголовок запроса |
[FromQuery] |
Параметр строки запроса |
[FromRoute] |
Данные маршрута из текущего запроса |
[FromServices] |
Служба запросов, внедренная в качестве параметра действия |
Warning
Не используйте [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.
Дополнительные ресурсы
- Типы возвращаемых действий контроллера в веб-API ASP.NET Core
- Обработка ошибок в api ASP.NET Core
- Пользовательские форматтеры в веб-API ASP.NET Core
- Форматирование данных ответа в веб-API ASP.NET Core
- документация по веб-API ASP.NET Core с помощью Swagger / OpenAPI
- Маршрутизация на действия контроллера в ASP.NET Core
- Создание веб-API с помощью ASP.NET Core
[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:
| Method | Notes |
|---|---|
| BadRequest | Возвращает код состояния 400. |
| NotFound | Возвращает код состояния 404. |
| PhysicalFile | Возвращает файл. |
| TryUpdateModelAsync | Вызывает привязку модели. |
| TryValidateModel | Вызывает проверку модели. |
Список всех доступных методов и свойств см. здесь: ControllerBase.
Attributes
Пространство имен 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);
}
Вот еще примеры доступных атрибутов:
| Attribute | Notes |
|---|---|
[Route] |
Определяет шаблон URL-адреса для контроллера или действия. |
[Bind] |
Задает префикс и свойства, которые добавляются для привязки модели. |
[HttpGet] |
Определяет действие, которое поддерживает команду действия HTTP GET. |
[Consumes] |
Указывает типы данных, которые принимает действие. |
[Produces] |
Указывает типы данных, которые возвращает действие. |
Список доступных атрибутов см. в пространстве имен Microsoft.AspNetCore.Mvc.
Атрибут ApiController
Атрибут [ApiController] можно применить к классу контроллера для включения следующих специализированных схем поведения API:
- Обязательная маршрутизация атрибутов
- Автоматические отклики HTTP 400
- Вывод параметров источника привязки
- Инферирование запросов с многокомпонентными данными формы
- Сведения о проблемах для кодов состояния ошибки Для использования функции Сведения о проблеме для кодов состояния ошибки требуется совместимая версия 2.2 и выше. Для реализации других функций требуется совместимая версия 2.1 и выше.
- Обязательная маршрутизация атрибутов
- Автоматические отклики HTTP 400
- Определение параметров источника привязки
- Вывод многокомпонентных запросов и запросов данных форм Для этих функций требуется совместимость версии 2.1 или более поздней.
Атрибут в определенных контроллерах
Атрибут [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
Отключение автоматического ответа 400
Чтобы отключить автоматическое поведение HTTP 400, задайте свойству SuppressModelStateInvalidFilter значение true. Добавьте выделенный ниже код в Startup.ConfigureServices:
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressConsumesConstraintForFormFileParameters = true;
options.SuppressInferBindingSourcesForParameters = true;
options.SuppressModelStateInvalidFilter = true;
});
Определение параметров источника привязки
Атрибут источника привязки определяет расположение, в котором находится значение параметра действия. Существуют следующие атрибуты источника привязки.
| Attribute | Источник привязки |
|---|---|
[FromBody] |
Основное содержание запроса |
[FromForm] |
Данные формы в тексте запроса |
[FromHeader] |
Заголовок запроса |
[FromQuery] |
Параметр строки запроса |
[FromRoute] |
Данные маршрута из текущего запроса |
[FromServices] |
Служба запросов, внедренная в качестве параметра действия |
Warning
Не используйте [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)
Note
В 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.
Дополнительные ресурсы
- Типы возвращаемых действий контроллера в веб-API ASP.NET Core
- Обработка ошибок в api ASP.NET Core
- Пользовательские форматтеры в веб-API ASP.NET Core
- Форматирование данных ответа в веб-API ASP.NET Core
- документация по веб-API ASP.NET Core с помощью Swagger / OpenAPI
- Маршрутизация на действия контроллера в ASP.NET Core
- Создание веб-API с помощью ASP.NET Core
ASP.NET Core