使用 ASP.NET Core 创建 Web API
作者:Scott Addie 和 Tom Dykstra
ASP.NET Core 支持使用 C# 创建 RESTful 服务,也称为 Web API。 若要处理请求,Web API 使用控制器。 Web API 中的控制器是派生自 ControllerBase
的类。 本文介绍了如何使用控制器处理 Web API 请求。
ControllerBase 类
Web API 包含一个或多个派生自 ControllerBase 的控制器类。 Web API 项目模板提供了一个入门版控制器:
[ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase
[Route("api/[controller]")] [ApiController] public class ValuesController : 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] |
指定某个操作返回的数据类型。 |
有关包含可用属性的列表,请参阅 Microsoft.AspNetCore.Mvc 命名空间。
ApiController 属性
[ApiController]
属性可应用于控制器类,以启用下述 API 特定的固定行为:
必须有兼容性版本 2.2 或更高版本,才能使用“错误状态代码的问题详细信息” 功能。 必须有兼容性版本 2.1 或更高版本,才能使用其他功能。
这些功能需要兼容性版本为 2.1 或更高版本。
特定控制器上的属性
[ApiController]
属性可应用于特定控制器,如项目模板中的以下示例所示:
[ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase
[Route("api/[controller]")] [ApiController] public class ValuesController : ControllerBase
多个控制器上的属性
在多个控制器上使用该属性的一种方法是创建通过 [ApiController]
属性批注的自定义基控制器类。 下述示例展示了自定义基类以及从其派生的控制器:
[ApiController] public class MyControllerBase : ControllerBase { }
[Produces(MediaTypeNames.Application.Json)] [Route("[controller]")] public class PetsController : MyControllerBase
[Produces(MediaTypeNames.Application.Json)] [Route("api/[controller]")] public class PetsController : MyControllerBase
程序集上的属性
如果将兼容性版本设置为 2.2 或更高版本,则 [ApiController]
属性可应用于程序集。 以这种方式进行注释,会将 web API 行为应用到程序集中的所有控制器。 无法针对单个控制器执行选择退出操作。 将程序集级别的属性应用于 Startup
类两侧的命名空间声明:
[assembly: ApiController] namespace WebApiSample { public class Startup { ... } }
特性路由要求
[ApiController]
属性使属性路由成为要求。 例如:
[ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase
不能通过由 Startup.Configure
中的 UseEndpoints
、UseMvc 或 UseMvcWithDefaultRoute 定义的传统路由访问操作。
[Route("api/[controller]")] [ApiController] public class ValuesController : ControllerBase
不能通过 UseMvc 定义的传统路由或通过 Startup.Configure
中的 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 规范。
记录自动 400 响应
请参阅如何对模型验证错误记录自动 400 响应 (aspnet/AspNetCore.Docs #12157)。
禁用自动 400 响应
若要禁用自动 400 行为,请将 SuppressModelStateInvalidFilter 属性设置为 true
。 将以下突出显示的代码添加到 Startup.ConfigureServices
:
services.AddControllers() .ConfigureApiBehaviorOptions(options => { options.SuppressConsumesConstraintForFormFileParameters = true; options.SuppressInferBindingSourcesForParameters = true; options.SuppressModelStateInvalidFilter = true; options.SuppressMapClientErrors = true; options.ClientErrorMapping[404].Link = "https://httpstatuses.com/404"; });
services.AddMvc() .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) .ConfigureApiBehaviorOptions(options => { options.SuppressConsumesConstraintForFormFileParameters = true; options.SuppressInferBindingSourcesForParameters = true; options.SuppressModelStateInvalidFilter = true; options.SuppressMapClientErrors = true; options.ClientErrorMapping[404].Link = "https://httpstatuses.com/404"; });
services.Configure<ApiBehaviorOptions>(options => { options.SuppressConsumesConstraintForFormFileParameters = true; options.SuppressInferBindingSourcesForParameters = true; options.SuppressModelStateInvalidFilter = true; });
绑定源参数推理
绑定源特性定义可找到操作参数值的位置。 存在以下绑定源特性:
特性 | 绑定源 |
---|---|
[FromBody] |
请求正文 |
[FromForm] |
请求正文中的表单数据 |
[FromHeader] |
请求标头 |
[FromQuery] |
请求查询字符串参数 |
[FromRoute] |
当前请求中的路由数据 |
[FromServices] |
作为操作参数插入的请求服务 |
警告
当值可能包含 %2f
(即 /
)时,请勿使用 [FromRoute]
。 %2f
不会转换为 /
(非转义形式)。 如果值可能包含 %2f
,则使用 [FromQuery]
。
如果没有 [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]
属性。
当操作拥有多个从请求正文中绑定的参数时,将会引发异常。 例如,以下所有操作方法签名都会导致异常:
[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.AddControllers() .ConfigureApiBehaviorOptions(options => { options.SuppressConsumesConstraintForFormFileParameters = true; options.SuppressInferBindingSourcesForParameters = true; options.SuppressModelStateInvalidFilter = true; options.SuppressMapClientErrors = true; options.ClientErrorMapping[404].Link = "https://httpstatuses.com/404"; });
services.AddMvc() .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) .ConfigureApiBehaviorOptions(options => { options.SuppressConsumesConstraintForFormFileParameters = true; options.SuppressInferBindingSourcesForParameters = true; options.SuppressModelStateInvalidFilter = true; options.SuppressMapClientErrors = true; options.ClientErrorMapping[404].Link = "https://httpstatuses.com/404"; });
services.Configure<ApiBehaviorOptions>(options => { options.SuppressConsumesConstraintForFormFileParameters = true; options.SuppressInferBindingSourcesForParameters = true; options.SuppressModelStateInvalidFilter = true; });
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[404].Link = "https://httpstatuses.com/404"; });
services.AddMvc() .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) .ConfigureApiBehaviorOptions(options => { options.SuppressConsumesConstraintForFormFileParameters = true; options.SuppressInferBindingSourcesForParameters = true; options.SuppressModelStateInvalidFilter = true; options.SuppressMapClientErrors = true; options.ClientErrorMapping[404].Link = "https://httpstatuses.com/404"; });
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
方法会生成带 ProblemDetails
正文的 HTTP 404 状态代码。 例如:
{ type: "https://tools.ietf.org/html/rfc7231#section-6.5.4", title: "Not Found", status: 404, traceId: "0HLHLV31KRN83:00000001" }
禁用 ProblemDetails 响应
当 SuppressMapClientErrors 属性设置为 true
时,会禁止自动创建 ProblemDetails
实例。 在 Startup.ConfigureServices
中添加下列代码:
services.AddControllers() .ConfigureApiBehaviorOptions(options => { options.SuppressConsumesConstraintForFormFileParameters = true; options.SuppressInferBindingSourcesForParameters = true; options.SuppressModelStateInvalidFilter = true; options.SuppressMapClientErrors = true; options.ClientErrorMapping[404].Link = "https://httpstatuses.com/404"; });
services.AddMvc() .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) .ConfigureApiBehaviorOptions(options => { options.SuppressConsumesConstraintForFormFileParameters = true; options.SuppressInferBindingSourcesForParameters = true; options.SuppressModelStateInvalidFilter = true; options.SuppressMapClientErrors = true; options.ClientErrorMapping[404].Link = "https://httpstatuses.com/404"; });
使用 [Consumes] 属性定义支持的请求内容类型
默认情况下,操作支持所有可用的请求内容类型。 例如,如果应用配置为同时支持 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
头发送的请求。
其他资源
上一篇:没有了