欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

使用 ASP.NET Core 创建 Web API

程序员文章站 2024-02-20 10:24:34
...

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

目录

ControllerBase 类

特性

ApiController 属性

特性路由要求

自动 HTTP 400 响应

绑定源参数推理

Multipart/form-data 请求推理

错误状态代码的问题详细信息


ControllerBase 类

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

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

不要通过从 Controller 类派生来创建 Web API 控制器。 Controller 派生自 ControllerBase,并添加对视图的支持,因此它用于处理 Web 页面,而不是 Web API 请求。 此规则有一个例外:如果打算为视图和 Web 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 命名空间提供可用于配置 Web 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] 指定某个操作返回的数据类型。

ApiController 属性

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

  • 特性路由要求
  • 自动 HTTP 400 响应
  • 绑定源参数推理
  • Multipart/form-data 请求推理
  • 错误状态代码的问题详细信息

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

  • 特性路由要求
  • 自动 HTTP 400 响应
  • 绑定源参数推理
  • Multipart/form-data 请求推理

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

特性路由要求

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

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

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

自动 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 类型:

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

要使自动和自定义响应保持一致,请调用 ValidationProblem 方法,而不是 BadRequest。 ValidationProblem 返回 ValidationProblemDetails 对象以及自动响应。


禁用自动 400 响应

若要禁用自动 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";
    });

绑定源参数推理

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

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

如果没有 [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;
}

FromBody 推理说明

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

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

  •  [FromBody] 对两者进行推断,因为它们是复杂类型。
  • [HttpPost]
    public IActionResult Action1(Product product, Order order)
  • [FromBody] 对一个进行归属,对另一个进行推断,因为它是复杂类型。
  • 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";
    });

Multipart/form-data 请求推理

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

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

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";
    });

错误状态代码的问题详细信息

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

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

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

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

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

禁用 ProblemDetails 响应

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

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

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

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

使用 [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 配置为处理发送到 https://localhost:5001/api/Consumes URL 的请求。 控制器的两个操作(PostJson 和 PostForm)都使用相同的 URL 处理 POST 请求。 如果 [Consumes] 属性不应用类型约束,则会抛出不明确匹配异常。

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

[-END-]