Обучение
Модуль
Создание веб-API с помощью контроллеров ASP.NET Core - Training
Создайте службу RESTful с помощью контроллеров ASP.NET Core, которые поддерживают операции создания, чтения, обновления и удаления (CRUD).
Этот браузер больше не поддерживается.
Выполните обновление до Microsoft Edge, чтобы воспользоваться новейшими функциями, обновлениями для системы безопасности и технической поддержкой.
ASP.NET Core поддерживает создание веб-API с помощью контроллеров или минимальных API. В веб-API контроллеры — это классы, производные от ControllerBase. Контроллеры активируются и удаляются на основе каждого запроса.
В этой статье показано, как использовать контроллеры для обработки веб-запросов API. Сведения о создании веб-API без контроллеров см. в руководстве по созданию минимального API с помощью ASP.NET Core.
Веб-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
.
Способ | Примечания. |
---|---|
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]
можно применить к классу контроллера для включения следующих специализированных схем поведения 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
Действия недоступны через обычные маршруты, определяемые UseEndpoints
, UseMvc или UseMvcWithDefaultRoute.
Благодаря атрибуту [ApiController]
ошибки проверки модели автоматически активируют отклик HTTP 400. В результате следующий код ненужен в методе действия:
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
Для выполнения предыдущей проверки ASP.NET Core MVC использует фильтр действий ModelStateInvalidFilter.
Для ответов 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
:
Чтобы обеспечить согласованность автоматических и настраиваемых ответов, вызовите метод ValidationProblem, а не BadRequest. ValidationProblem
возвращает объект ValidationProblemDetails, а также автоматический ответ.
Чтобы регистрировать автоматические ответы 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, задайте свойству 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] |
Служба запросов, внедренная в качестве параметра действия |
[AsParameters] |
Параметры методов |
Предупреждение
Не используйте [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]
не определен для простых типов, таких как 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]
к параметру не нужно. В следующем коде оба действия возвращают время:
[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 из внедрения зависимостей или из других источников.
Механизм вывода источника привязки параметров действия контроллера API использует следующие правила:
BindingInfo.BindingSource
не перезаписывается.BindingSource.Services
.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
для кодов состояния ошибок можно, задав свойству 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();
По умолчанию действие поддерживает все доступные типы содержимого запросов. Например, если в приложении включена поддержка форматировщиков входных данных JSON и XML, действие будет поддерживать несколько типов содержимого, включая application/json
и application/xml
.
Атрибут [Consumes] позволяет выполнять действие для ограничения поддерживаемых типов содержимого запросов. Примените атрибут [Consumes]
к действию или контроллеру, указав один или несколько типов содержимого:
[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)
В приведенном выше коде действие CreateProduct
указывает тип содержимого application/xml
. Запросы, направляемые в это действие, должны определять заголовок Content-Type
application/xml
. Запросы, не определяющие заголовок Content-Type
application/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-Type
application/json
. Действие PostForm
обрабатывает запросы, отправленные с заголовком Content-Type
application/x-www-form-urlencoded
.
ASP.NET Core поддерживает создание веб-API с помощью контроллеров или минимальных API. В веб-API контроллеры — это классы, производные от ControllerBase. В этой статье показано, как использовать контроллеры для обработки веб-запросов API. Сведения о создании веб-API без контроллеров см. в руководстве по созданию минимального API с помощью ASP.NET Core.
Веб-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
.
Способ | Примечания. |
---|---|
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]
можно применить к классу контроллера для включения следующих специализированных схем поведения 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
Действия недоступны через обычные маршруты, определяемые UseEndpoints
, UseMvc или UseMvcWithDefaultRoute.
Благодаря атрибуту [ApiController]
ошибки проверки модели автоматически активируют отклик HTTP 400. В результате следующий код ненужен в методе действия:
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
Для выполнения предыдущей проверки ASP.NET Core MVC использует фильтр действий ModelStateInvalidFilter.
Следующий текст ответа является примером сериализованного типа:
{
"": [
"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
:
Чтобы обеспечить согласованность автоматических и настраиваемых ответов, вызовите метод ValidationProblem, а не BadRequest. ValidationProblem
возвращает объект ValidationProblemDetails, а также автоматический ответ.
Чтобы регистрировать автоматические ответы 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, задайте свойству 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]
выводится для параметров сложного типа, не зарегистрированных в контейнере DI. Исключением из правила зависимости [FromBody]
является любой сложный встроенный тип со специальным значением, такой как IFormCollection и CancellationToken. Код определения источника привязки игнорирует эти особые типы.[FromForm]
выводится для параметров действия с типом IFormFile и IFormFileCollection. Он не выводится ни для каких простых или определяемых пользователем типов.[FromRoute]
выводится для любого имени параметра действия, соответствующего параметру в шаблоне маршрута. Если параметру действия соответствуют несколько маршрутов, любое значение маршрута рассматривается как [FromRoute]
.[FromQuery]
выводится для любых других параметров действия.[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
для кодов состояния ошибок можно, задав свойству 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();
По умолчанию действие поддерживает все доступные типы содержимого запросов. Например, если в приложении включена поддержка форматировщиков входных данных JSON и XML, действие будет поддерживать несколько типов содержимого, включая application/json
и application/xml
.
Атрибут [Consumes] позволяет выполнять действие для ограничения поддерживаемых типов содержимого запросов. Примените атрибут [Consumes]
к действию или контроллеру, указав один или несколько типов содержимого:
[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)
В приведенном выше коде действие CreateProduct
указывает тип содержимого application/xml
. Запросы, направляемые в это действие, должны определять заголовок Content-Type
application/xml
. Запросы, не определяющие заголовок Content-Type
application/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-Type
application/json
. Действие PostForm
обрабатывает запросы, отправленные с заголовком Content-Type
application/x-www-form-urlencoded
.
ASP.NET Core поддерживает создание служб RESTful, также известных как веб-API, с помощью C#. Для обработки запросов веб-API использует контроллеры. В веб-API контроллеры — это классы, производные от ControllerBase
. В этой статье показано, как использовать контроллеры для обработки веб-запросов API.
Просмотреть или скачать образец кода. (Инструкция по скачиванию.)
Веб-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]
можно применить к классу контроллера для включения следующих специализированных схем поведения 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
.
Благодаря атрибуту [ApiController]
ошибки проверки модели автоматически активируют отклик HTTP 400. В результате следующий код ненужен в методе действия:
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
Для выполнения предыдущей проверки ASP.NET Core MVC использует фильтр действий ModelStateInvalidFilter.
Следующий текст запроса является примером сериализованного типа:
{
"": [
"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
:
Чтобы обеспечить согласованность автоматических и настраиваемых ответов, вызовите метод ValidationProblem, а не BadRequest. ValidationProblem
возвращает объект ValidationProblemDetails, а также автоматический ответ.
Чтобы регистрировать автоматические ответы 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, задайте свойству 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]
не определен для простых типов, таких как 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
для кодов состояния ошибок можно, задав свойству 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;
});
По умолчанию действие поддерживает все доступные типы содержимого запросов. Например, если в приложении включена поддержка форматировщиков входных данных JSON и XML, действие будет поддерживать несколько типов содержимого, включая application/json
и application/xml
.
Атрибут [Consumes] позволяет выполнять действие для ограничения поддерживаемых типов содержимого запросов. Примените атрибут [Consumes]
к действию или контроллеру, указав один или несколько типов содержимого:
[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)
В приведенном выше коде действие CreateProduct
указывает тип содержимого application/xml
. Запросы, направляемые в это действие, должны определять заголовок Content-Type
application/xml
. Запросы, не определяющие заголовок Content-Type
application/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-Type
application/json
. Действие PostForm
обрабатывает запросы, отправленные с заголовком Content-Type
application/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]
можно применить к классу контроллера для включения следующих специализированных схем поведения 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
.
Благодаря атрибуту [ApiController]
ошибки проверки модели автоматически активируют отклик HTTP 400. В результате следующий код ненужен в методе действия:
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
Для выполнения предыдущей проверки ASP.NET Core MVC использует фильтр действий ModelStateInvalidFilter.
Если задана версия совместимости 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
:
Чтобы обеспечить согласованность автоматических и настраиваемых ответов, вызовите метод ValidationProblem, а не BadRequest. ValidationProblem
возвращает объект ValidationProblemDetails, а также автоматический ответ.
См. описание проблемы записи в журнал автоматических ответов HTTP 400 для ошибок проверки модели (aspnet/AspNetCore.Docs#12157).
Чтобы отключить автоматическую активацию отклика 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]
не определен для простых типов, таких как 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
для кодов состояния ошибок можно, задав свойству SuppressMapClientErrors значение true
. Добавьте следующий код в Startup.ConfigureServices
:
По умолчанию действие поддерживает все доступные типы содержимого запросов. Например, если в приложении включена поддержка форматировщиков входных данных JSON и XML, действие будет поддерживать несколько типов содержимого, включая application/json
и application/xml
.
Атрибут [Consumes] позволяет выполнять действие для ограничения поддерживаемых типов содержимого запросов. Примените атрибут [Consumes]
к действию или контроллеру, указав один или несколько типов содержимого:
[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)
В приведенном выше коде действие CreateProduct
указывает тип содержимого application/xml
. Запросы, направляемые в это действие, должны определять заголовок Content-Type
application/xml
. Запросы, не определяющие заголовок Content-Type
application/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-Type
application/json
. Действие PostForm
обрабатывает запросы, отправленные с заголовком Content-Type
application/x-www-form-urlencoded
.
Отзыв о ASP.NET Core
ASP.NET Core — это проект с открытым исходным кодом. Выберите ссылку, чтобы оставить отзыв:
Обучение
Модуль
Создание веб-API с помощью контроллеров ASP.NET Core - Training
Создайте службу RESTful с помощью контроллеров ASP.NET Core, которые поддерживают операции создания, чтения, обновления и удаления (CRUD).