使用 ASP.NET Core 创建 Web APICreate web APIs with ASP.NET Core

本文内容

作者:Scott AddieTom Dykstra

ASP.NET Core 支持使用 C# 创建 RESTful 服务,也称为 Web API。若要处理请求,Web API 使用控制器。Web API 中的控制器是派生自 ControllerBase 的类。本文介绍了如何使用控制器处理 Web API 请求。

查看或下载示例代码下载方法)。

ControllerBase 类ControllerBase class

Web API 包含一个或多个派生自 ControllerBase 的控制器类。Web API 项目模板提供了一个入门版控制器:

  1. [ApiController]
  2. [Route("[controller]")]
  3. public class WeatherForecastController : ControllerBase
  1. [Route("api/[controller]")]
  2. [ApiController]
  3. public class ValuesController : ControllerBase

不要通过从 Controller 类派生来创建 Web API 控制器。Controller 派生自 ControllerBase,并添加对视图的支持,因此它用于处理 Web 页面,而不是 Web API 请求。此规则有一个例外:如果打算为视图和 Web API 使用相同的控制器,则从 Controller 派生控制器。

ControllerBase 类提供了很多用于处理 HTTP 请求的属性和方法。例如,ControllerBase.CreatedAtAction 返回 201 状态代码:

  1. [HttpPost]
  2. [ProducesResponseType(StatusCodes.Status201Created)]
  3. [ProducesResponseType(StatusCodes.Status400BadRequest)]
  4. public ActionResult<Pet> Create(Pet pet)
  5. {
  6. pet.Id = _petsInMemoryStore.Any() ?
  7. _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
  8. _petsInMemoryStore.Add(pet);
  9. return CreatedAtAction(nameof(GetById), new { id = pet.Id }, pet);
  10. }

下面是 ControllerBase 提供的方法的更多示例。

方法说明
BadRequest返回 400 状态代码。
NotFound返回 404 状态代码。
PhysicalFile返回文件。
TryUpdateModelAsync调用模型绑定
TryValidateModel调用模型验证

有关可用方法和属性的列表,请参阅 ControllerBase

特性Attributes

Microsoft.AspNetCore.Mvc 命名空间提供可用于配置 Web API 控制器的行为和操作方法的属性。下述示例使用属性来指定受支持的 HTTP 操作谓词和所有可返回的已知 HTTP 状态代码:

  1. [HttpPost]
  2. [ProducesResponseType(StatusCodes.Status201Created)]
  3. [ProducesResponseType(StatusCodes.Status400BadRequest)]
  4. public ActionResult<Pet> Create(Pet pet)
  5. {
  6. pet.Id = _petsInMemoryStore.Any() ?
  7. _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
  8. _petsInMemoryStore.Add(pet);
  9. return CreatedAtAction(nameof(GetById), new { id = pet.Id }, pet);
  10. }

以下是可用属性的更多示例。

特性说明
[Route]指定控制器或操作的 URL 模式。
[Bind]指定要包含的前缀和属性,以进行模型绑定。
[HttpGet]标识支持 HTTP GET 操作谓词的操作。
[Consumes]指定某个操作接受的数据类型。
[Produces]指定某个操作返回的数据类型。

有关包含可用属性的列表,请参阅 Microsoft.AspNetCore.Mvc 命名空间。

ApiController 属性ApiController attribute

[ApiController] 属性可应用于控制器类,以启用下述 API 特定的固定行为:

必须有兼容性版本 2.2 或更高版本,才能使用“错误状态代码的问题详细信息” 功能。必须有兼容性版本 2.1 或更高版本,才能使用其他功能。

这些功能需要兼容性版本为 2.1 或更高版本。

特定控制器上的属性Attribute on specific controllers

[ApiController] 属性可应用于特定控制器,如项目模板中的以下示例所示:

  1. [ApiController]
  2. [Route("[controller]")]
  3. public class WeatherForecastController : ControllerBase
  1. [Route("api/[controller]")]
  2. [ApiController]
  3. public class ValuesController : ControllerBase

多个控制器上的属性Attribute on multiple controllers

在多个控制器上使用该属性的一种方法是创建通过 [ApiController] 属性批注的自定义基控制器类。下述示例展示了自定义基类以及从其派生的控制器:

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

程序集上的属性Attribute on an assembly

如果将兼容性版本设置为 2.2 或更高版本,则 [ApiController] 属性可应用于程序集。以这种方式进行注释,会将 web API 行为应用到程序集中的所有控制器。无法针对单个控制器执行选择退出操作。将程序集级别的属性应用于 Startup 类两侧的命名空间声明:

  1. [assembly: ApiController]
  2. namespace WebApiSample
  3. {
  4. public class Startup
  5. {
  6. ...
  7. }
  8. }

特性路由要求Attribute routing requirement

[ApiController] 属性使属性路由成为要求。例如:

  1. [ApiController]
  2. [Route("[controller]")]
  3. public class WeatherForecastController : ControllerBase

不能通过由 Startup.Configure 中的 UseEndpointsUseMvcUseMvcWithDefaultRoute 定义的传统路由访问操作。

  1. [Route("api/[controller]")]
  2. [ApiController]
  3. public class ValuesController : ControllerBase

不能通过 UseMvc 定义的传统路由或通过 Startup.Configure 中的 UseMvcWithDefaultRoute 访问操作。

自动 HTTP 400 响应Automatic HTTP 400 responses

[ApiController] 属性使模型验证错误自动触发 HTTP 400 响应。因此,操作方法中不需要以下代码:

  1. if (!ModelState.IsValid)
  2. {
  3. return BadRequest(ModelState);
  4. }

ASP.NET Core MVC 使用 ModelStateInvalidFilter 操作筛选器来执行上述检查。

默认 BadRequest 响应Default BadRequest response

使用 2.1 的兼容性版本时,HTTP 400 响应的默认响应类型为 SerializableError下述请求正文是序列化类型的示例:

  1. {
  2. "": [
  3. "A non-empty request body is required."
  4. ]
  5. }

使用 2.2 或更高版本的兼容性版本时,HTTP 400 响应的默认响应类型为 ValidationProblemDetails下述请求正文是序列化类型的示例:

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

ValidationProblemDetails 类型:

  • 提供计算机可读的格式来指定 Web API 响应中的错误。
  • 符合 RFC 7807 规范

记录自动 400 响应Log automatic 400 responses

请参阅如何对模型验证错误记录自动 400 响应 (aspnet/AspNetCore.Docs #12157)

禁用自动 400 响应Disable automatic 400 response

若要禁用自动 400 行为,请将 SuppressModelStateInvalidFilter 属性设置为 true将以下突出显示的代码添加到 Startup.ConfigureServices

  1. services.AddControllers()
  2. .ConfigureApiBehaviorOptions(options =>
  3. {
  4. options.SuppressConsumesConstraintForFormFileParameters = true;
  5. options.SuppressInferBindingSourcesForParameters = true;
  6. options.SuppressModelStateInvalidFilter = true;
  7. options.SuppressMapClientErrors = true;
  8. options.ClientErrorMapping[404].Link =
  9. "https://httpstatuses.com/404";
  10. });
  1. services.AddMvc()
  2. .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
  3. .ConfigureApiBehaviorOptions(options =>
  4. {
  5. options.SuppressConsumesConstraintForFormFileParameters = true;
  6. options.SuppressInferBindingSourcesForParameters = true;
  7. options.SuppressModelStateInvalidFilter = true;
  8. options.SuppressMapClientErrors = true;
  9. options.ClientErrorMapping[404].Link =
  10. "https://httpstatuses.com/404";
  11. });
  1. services.Configure<ApiBehaviorOptions>(options =>
  2. {
  3. options.SuppressConsumesConstraintForFormFileParameters = true;
  4. options.SuppressInferBindingSourcesForParameters = true;
  5. options.SuppressModelStateInvalidFilter = true;
  6. });

绑定源参数推理Binding source parameter inference

绑定源特性定义可找到操作参数值的位置。存在以下绑定源特性:

特性绑定源
[FromBody]请求正文
[FromForm]请求正文中的表单数据
[FromHeader]请求标头
[FromQuery]请求查询字符串参数
[FromRoute]当前请求中的路由数据
[FromServices]作为操作参数插入的请求服务

警告

当值可能包含 %2f(即 /)时,请勿使用 [FromRoute]%2f 不会转换为 /(非转义形式)。如果值可能包含 %2f,则使用 [FromQuery]

如果没有 [ApiController] 属性或诸如 [FromQuery] 的绑定源属性,ASP.NET Core 运行时会尝试使用复杂对象模型绑定器。复杂对象模型绑定器按已定义顺序从值提供程序拉取数据。

在下面的示例中,[FromQuery] 特性指示 discontinuedOnly 参数值在请求 URL 的查询字符串中提供:

  1. [HttpGet]
  2. public ActionResult<List<Product>> Get(
  3. [FromQuery] bool discontinuedOnly = false)
  4. {
  5. List<Product> products = null;
  6. if (discontinuedOnly)
  7. {
  8. products = _productsInMemoryStore.Where(p => p.IsDiscontinued).ToList();
  9. }
  10. else
  11. {
  12. products = _productsInMemoryStore;
  13. }
  14. return products;
  15. }

[ApiController] 属性将推理规则应用于操作参数的默认数据源。借助这些规则,无需通过将属性应用于操作参数来手动识别绑定源。绑定源推理规则的行为如下:

  • [FromBody] 针对复杂类型参数进行推断。[FromBody] 不适用于具有特殊含义的任何复杂的内置类型,如 IFormCollectionCancellationToken。绑定源推理代码将忽略这些特殊类型。
  • [FromForm] 针对 IFormFileIFormFileCollection 类型的操作参数进行推断。该特性不针对任何简单类型或用户定义类型进行推断。
  • [FromRoute] 针对与路由模板中的参数相匹配的任何操作参数名称进行推断。当多个路由与一个操作参数匹配时,任何路由值都视为 [FromRoute]
  • [FromQuery] 针对任何其他操作参数进行推断。

FromBody 推理说明FromBody inference notes

对于简单类型(例如 stringint),推断不出 [FromBody]因此,如果需要该功能,对于简单类型,应使用 [FromBody] 属性。

当操作拥有多个从请求正文中绑定的参数时,将会引发异常。例如,以下所有操作方法签名都会导致异常:

  • [FromBody] 对两者进行推断,因为它们是复杂类型。
  1. [HttpPost]
  2. public IActionResult Action1(Product product, Order order)
  • [FromBody] 对一个进行归属,对另一个进行推断,因为它是复杂类型。
  1. [HttpPost]
  2. public IActionResult Action2(Product product, [FromBody] Order order)
  • [FromBody] 对两者进行归属。
  1. [HttpPost]
  2. public IActionResult Action3([FromBody] Product product, [FromBody] Order order)

备注

在 ASP.NET Core 2.1 中,集合类型参数(如列表和数组)被不正确地推断为 [FromQuery]若要从请求正文中绑定参数,应对这些参数使用 [FromBody] 属性。此行为在 ASP.NET Core 2.2 或更高版本中得到了更正,其中集合类型参数默认被推断为从正文中绑定。

禁用推理规则Disable inference rules

若要禁用绑定源推理,请将 SuppressInferBindingSourcesForParameters 设置为 trueStartup.ConfigureServices 中添加下列代码:

  1. services.AddControllers()
  2. .ConfigureApiBehaviorOptions(options =>
  3. {
  4. options.SuppressConsumesConstraintForFormFileParameters = true;
  5. options.SuppressInferBindingSourcesForParameters = true;
  6. options.SuppressModelStateInvalidFilter = true;
  7. options.SuppressMapClientErrors = true;
  8. options.ClientErrorMapping[404].Link =
  9. "https://httpstatuses.com/404";
  10. });
  1. services.AddMvc()
  2. .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
  3. .ConfigureApiBehaviorOptions(options =>
  4. {
  5. options.SuppressConsumesConstraintForFormFileParameters = true;
  6. options.SuppressInferBindingSourcesForParameters = true;
  7. options.SuppressModelStateInvalidFilter = true;
  8. options.SuppressMapClientErrors = true;
  9. options.ClientErrorMapping[404].Link =
  10. "https://httpstatuses.com/404";
  11. });
  1. services.Configure<ApiBehaviorOptions>(options =>
  2. {
  3. options.SuppressConsumesConstraintForFormFileParameters = true;
  4. options.SuppressInferBindingSourcesForParameters = true;
  5. options.SuppressModelStateInvalidFilter = true;
  6. });

Multipart/form-data 请求推理Multipart/form-data request inference

使用 [FromForm] 属性批注操作参数时,[ApiController] 属性应用推理规则。将推断 multipart/form-data 请求内容类型。

要禁用默认行为,请在 Startup.ConfigureServices 中将 SuppressConsumesConstraintForFormFileParameters 属性设置为 true

  1. services.AddControllers()
  2. .ConfigureApiBehaviorOptions(options =>
  3. {
  4. options.SuppressConsumesConstraintForFormFileParameters = true;
  5. options.SuppressInferBindingSourcesForParameters = true;
  6. options.SuppressModelStateInvalidFilter = true;
  7. options.SuppressMapClientErrors = true;
  8. options.ClientErrorMapping[404].Link =
  9. "https://httpstatuses.com/404";
  10. });
  1. services.AddMvc()
  2. .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
  3. .ConfigureApiBehaviorOptions(options =>
  4. {
  5. options.SuppressConsumesConstraintForFormFileParameters = true;
  6. options.SuppressInferBindingSourcesForParameters = true;
  7. options.SuppressModelStateInvalidFilter = true;
  8. options.SuppressMapClientErrors = true;
  9. options.ClientErrorMapping[404].Link =
  10. "https://httpstatuses.com/404";
  11. });
  1. services.Configure<ApiBehaviorOptions>(options =>
  2. {
  3. options.SuppressConsumesConstraintForFormFileParameters = true;
  4. options.SuppressInferBindingSourcesForParameters = true;
  5. options.SuppressModelStateInvalidFilter = true;
  6. });

错误状态代码的问题详细信息Problem details for error status codes

当兼容性版本为 2.2 或更高版本时,MVC 会将错误结果(状态代码为 400 或更高的结果)转换为状态代码为 ProblemDetails 的结果。ProblemDetails 类型基于 RFC 7807 规范,用于提供 HTTP 响应中计算机可读的错误详细信息。

考虑在控制器操作中使用以下代码:

  1. if (pet == null)
  2. {
  3. return NotFound();
  4. }

NotFound 方法会生成带 ProblemDetails 正文的 HTTP 404 状态代码。例如:

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

禁用 ProblemDetails 响应Disable ProblemDetails response

SuppressMapClientErrors 属性设置为 true 时,会禁止自动创建错误状态代码的 ProblemDetailsStartup.ConfigureServices 中添加下列代码:

  1. services.AddControllers()
  2. .ConfigureApiBehaviorOptions(options =>
  3. {
  4. options.SuppressConsumesConstraintForFormFileParameters = true;
  5. options.SuppressInferBindingSourcesForParameters = true;
  6. options.SuppressModelStateInvalidFilter = true;
  7. options.SuppressMapClientErrors = true;
  8. options.ClientErrorMapping[404].Link =
  9. "https://httpstatuses.com/404";
  10. });
  1. services.AddMvc()
  2. .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
  3. .ConfigureApiBehaviorOptions(options =>
  4. {
  5. options.SuppressConsumesConstraintForFormFileParameters = true;
  6. options.SuppressInferBindingSourcesForParameters = true;
  7. options.SuppressModelStateInvalidFilter = true;
  8. options.SuppressMapClientErrors = true;
  9. options.ClientErrorMapping[404].Link =
  10. "https://httpstatuses.com/404";
  11. });

使用 [Consumes] 属性定义支持的请求内容类型Define supported request content types with the [Consumes] attribute

默认情况下,操作支持所有可用的请求内容类型。例如,如果应用配置为同时支持 JSON 和 XML 输入格式化程序,那么操作支持多种内容类型,其中包括 application/jsonapplication/xml

使用 [Consumes] 属性,操作可以限制支持的请求内容类型。[Consumes] 属性应用于操作或控制器,同时指定一个或多个内容类型:

  1. [HttpPost]
  2. [Consumes("application/xml")]
  3. public IActionResult CreateProduct(Product product)

在上面的代码中,CreateProduct 操作指定内容类型 application/xml路由到此操作的请求必须指定 application/xmlContent-Type 头。如果请求未指定 application/xmlContent-Type 头,会生成 415 不支持的媒体类型响应。

使用 [Consumes] 属性,操作可以通过应用类型约束,根据传入请求的内容类型来影响它的选择。请看下面的示例:

  1. [ApiController]
  2. [Route("api/[controller]")]
  3. public class ConsumesController : ControllerBase
  4. {
  5. [HttpPost]
  6. [Consumes("application/json")]
  7. public IActionResult PostJson(IEnumerable<int> values) =>
  8. Ok(new { Consumes = "application/json", Values = values });
  9. [HttpPost]
  10. [Consumes("application/x-www-form-urlencoded")]
  11. public IActionResult PostForm([FromForm] IEnumerable<int> values) =>
  12. Ok(new { Consumes = "application/x-www-form-urlencoded", Values = values });
  13. }

在上面的代码中,ConsumesController 配置为处理发送到 https://localhost:5001/api/Consumes URL 的请求。控制器的两个操作(PostJsonPostForm)都使用相同的 URL 处理 POST 请求。如果 [Consumes] 属性不应用类型约束,则会抛出不明确匹配异常。

[Consumes] 属性应用于两个操作。PostJson 操作处理使用 application/jsonContent-Type 头发送的请求。PostForm 操作处理使用 application/x-www-form-urlencodedContent-Type 头发送的请求。

其他资源Additional resources