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

作者:Scott AddieTom DykstraBy Scott Addie and Tom Dykstra

ASP.NET Core 支持使用 C# 创建 RESTful 服务,也称为 Web API。ASP.NET Core supports creating RESTful services, also known as web APIs, using C#. 若要处理请求,Web API 使用控制器。To handle requests, a web API uses controllers. Web API 中的控制器是派生自 ControllerBase 的类。Controllers in a web API are classes that derive from ControllerBase. 本文介绍了如何使用控制器处理 API 请求。This article shows how to use controllers for handling API requests.

查看或下载示例代码View or download sample code. 下载方法)。(How to download).

ControllerBase 类ControllerBase class

Web API 有一个或多个派生自 ControllerBase 的控制器类。A web API has one or more controller classes that derive from ControllerBase. 例如,Web API 项目模板创建一个 Values 控制器:For example, the web API project template creates a Values controller:

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase

不要通过从 Controller 基类派生来创建 Web API 控制器。Don't create a web API controller by deriving from the Controller base class. Controller 派生自 ControllerBase,并添加对视图的支持,因此它用于处理 Web 页面,而不是 Web API 请求。Controller derives from ControllerBase and adds support for views, so it's for handling web pages, not web API requests. 此规则有一个例外:如果打算为视图和 API 使用相同的控制器,则从 Controller 派生控制器。There's an exception to this rule: if you plan to use the same controller for both views and APIs, derive it from Controller.

ControllerBase 类提供了很多用于处理 HTTP 请求的属性和方法。The ControllerBase class provides many properties and methods that are useful for handling HTTP requests. 例如,ControllerBase.CreatedAtAction 返回 201 状态代码:For example, ControllerBase.CreatedAtAction returns a 201 status code:

[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 提供的方法的更多示例。Here are some more examples of methods that ControllerBase provides.

方法Method 说明Notes
BadRequest 返回 400 状态代码。Returns 400 status code.
NotFound 返回 404 状态代码。Returns 404 status code.
PhysicalFile 返回文件。Returns a file.
TryUpdateModelAsync 调用模型绑定Invokes model binding.
TryValidateModel 调用模型验证Invokes model validation.

有关可用方法和属性的列表,请参阅 ControllerBaseFor a list of all available methods and properties, see ControllerBase.

特性Attributes

Microsoft.AspNetCore.Mvc 命名空间提供可用于配置 Web API 控制器的行为和操作方法的属性。The Microsoft.AspNetCore.Mvc namespace provides attributes that can be used to configure the behavior of web API controllers and action methods. 以下示例使用这些属性来指定接受的 HTTP 方法和返回的状态代码:The following example uses attributes to specify the HTTP method accepted and the status codes returned:

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

以下是可用属性的更多示例。Here are some more examples of attributes that are available.

特性Attribute 说明Notes
[Route][Route] 指定控制器或操作的 URL 模式。Specifies URL pattern for a controller or action.
[Bind][Bind] 指定要包含的前缀和属性,以进行模型绑定。Specifies prefix and properties to include for model binding.
[HttpGet][HttpGet] 标识支持 HTTP GET 方法的操作。Identifies an action that supports the HTTP GET method.
[Consumes][Consumes] 指定某个操作接受的数据类型。Specifies data types that an action accepts.
[Produces][Produces] 指定某个操作返回的数据类型。Specifies data types that an action returns.

有关包含可用属性的列表,请参阅 Microsoft.AspNetCore.Mvc 命名空间。For a list that includes the available attributes, see the Microsoft.AspNetCore.Mvc namespace.

ApiController 属性ApiController attribute

[ApiController] 属性可应用于控制器类,以启用 API 特定的行为:The [ApiController] attribute can be applied to a controller class to enable API-specific behaviors:

这些功能需要兼容性版本为 2.1 或更高版本。These features require a compatibility version of 2.1 or later.

特定控制器上的 ApiControllerApiController on specific controllers

[ApiController] 属性可应用于特定控制器,如项目模板中的以下示例所示:The [ApiController] attribute can be applied to specific controllers, as in the following example from the project template:

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase

多个控制器上的 ApiControllerApiController on multiple controllers

在多个控制器上使用该属性的一种方法是创建通过 [ApiController] 属性批注的自定义基控制器类。One approach to using the attribute on more than one controller is to create a custom base controller class annotated with the [ApiController] attribute. 下面这个示例显示了自定义基类和从其派生的控制器:Here's an example showing a custom base class and a controller that derives from it:

[ApiController]
public class MyControllerBase : ControllerBase
{
}
[Produces("application/json")]
[Route("api/[controller]")]
public class PetsController : MyControllerBase

程序集上的 ApiControllerApiController on an assembly

如果将兼容性版本设置为 2.2 或更高版本,则 [ApiController] 属性可应用于程序集。If compatibility version is set to 2.2 or later, the [ApiController] attribute can be applied to an assembly. 以这种方式进行注释,会将 web API 行为应用到程序集中的所有控制器。Annotation in this manner applies web API behavior to all controllers in the assembly. 无法针对单个控制器执行选择退出操作。There's no way to opt out for individual controllers. 将程序集级别的属性应用于以下示例所示的 Startup 类:Apply the assembly-level attribute to the Startup class as shown in the following example:

[assembly: ApiController]
namespace WebApiSample
{
    public class Startup
    {
        ...
    }
}

特性路由要求Attribute routing requirement

ApiController 属性使属性路由成为要求。The ApiController attribute makes attribute routing a requirement. 例如:For example:

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase

不能通过 UseMvc 定义的传统路由或通过 Startup.Configure 中的 UseMvcWithDefaultRoute 访问操作。Actions are inaccessible via conventional routes defined by UseMvc or UseMvcWithDefaultRoute in Startup.Configure.

自动 HTTP 400 响应Automatic HTTP 400 responses

ApiController 属性使模型验证错误自动触发 HTTP 400 响应。The ApiController attribute makes model validation errors automatically trigger an HTTP 400 response. 因此,操作方法中不需要以下代码:Consequently, the following code is unnecessary in an action method:

if (!ModelState.IsValid)
{
    return BadRequest(ModelState);
}

默认 BadRequest 响应Default BadRequest response

使用 2.2 或更高版本的兼容性版本时,HTTP 400 响应的默认响应类型为 ValidationProblemDetailsWith a compatibility version of 2.2 or later, the default response type for HTTP 400 responses is ValidationProblemDetails. ValidationProblemDetails 类型符合 RFC 7807 规范The ValidationProblemDetails type complies with the RFC 7807 specification.

若要将默认响应更改为 SerializableError,请在 Startup.ConfigureServices 中将 SuppressUseValidationProblemDetailsForInvalidModelStateResponses 属性设置为 true,如以下示例所示:To change the default response to SerializableError, set the SuppressUseValidationProblemDetailsForInvalidModelStateResponses property to true in Startup.ConfigureServices, as shown in the following example:

services.AddMvc()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.SuppressUseValidationProblemDetailsForInvalidModelStateResponses = true;
        options.ClientErrorMapping[404].Link =
            "https://httpstatuses.com/404";
    });

自定义 BadRequest 响应Customize BadRequest response

若要自定义验证错误引发的响应,请使用 InvalidModelStateResponseFactoryTo customize the response that results from a validation error, use InvalidModelStateResponseFactory. 将以下突出显示的代码添加到 services.AddMvc().SetCompatibilityVersion 后面:Add the following highlighted code after services.AddMvc().SetCompatibilityVersion:

services.AddMvc()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
    .ConfigureApiBehaviorOptions(options =>
    {
        options.InvalidModelStateResponseFactory = context =>
        {
            var problemDetails = new ValidationProblemDetails(context.ModelState)
            {
                Type = "https://contoso.com/probs/modelvalidation",
                Title = "One or more model validation errors occurred.",
                Status = StatusCodes.Status400BadRequest,
                Detail = "See the errors property for details.",
                Instance = context.HttpContext.Request.Path
            };

            return new BadRequestObjectResult(problemDetails)
            {
                ContentTypes = { "application/problem+json" }
            };
        };
    });

记录自动 400 响应Log automatic 400 responses

请参阅如何对模型验证错误记录自动 400 响应 (aspnet/AspNetCore.Docs #12157)See How to log automatic 400 responses on model validation errors (aspnet/AspNetCore.Docs #12157).

禁用自动 400Disable automatic 400

若要禁用自动 400 行为,请将 SuppressModelStateInvalidFilter 属性设置为 trueTo disable the automatic 400 behavior, set the SuppressModelStateInvalidFilter property to true. Startup.ConfigureServices 中以下突出显示的代码添加到 services.AddMvc().SetCompatibilityVersion 后面:Add the following highlighted code in Startup.ConfigureServices after services.AddMvc().SetCompatibilityVersion:

services.AddMvc()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.SuppressUseValidationProblemDetailsForInvalidModelStateResponses = true;
        options.ClientErrorMapping[404].Link =
            "https://httpstatuses.com/404";
    });

绑定源参数推理Binding source parameter inference

绑定源特性定义可找到操作参数值的位置。A binding source attribute defines the location at which an action parameter's value is found. 存在以下绑定源特性:The following binding source attributes exist:

特性Attribute 绑定源Binding source
[FromBody][FromBody] 请求正文Request body
[FromForm][FromForm] 请求正文中的表单数据Form data in the request body
[FromHeader][FromHeader] 请求标头Request header
[FromQuery][FromQuery] 请求查询字符串参数Request query string parameter
[FromRoute][FromRoute] 当前请求中的路由数据Route data from the current request
[FromServices][FromServices] 作为操作参数插入的请求服务The request service injected as an action parameter

警告

当值可能包含 %2f(即 /)时,请勿使用 [FromRoute]Don't use [FromRoute] when values might contain %2f (that is /). %2f 不会转换为 /(非转移形式)。%2f won't be unescaped to /. 如果值可能包含 %2f,则使用 [FromQuery]Use [FromQuery] if the value might contain %2f.

如果没有 [ApiController] 属性或诸如 [FromQuery] 的绑定源属性,ASP.NET Core 运行时会尝试使用复杂对象模型绑定器。Without the [ApiController] attribute or binding source attributes like [FromQuery], the ASP.NET Core runtime attempts to use the complex object model binder. 复杂对象模型绑定器按已定义顺序从值提供程序拉取数据。The complex object model binder pulls data from value providers in a defined order.

在下面的示例中,[FromQuery] 特性指示 discontinuedOnly 参数值在请求 URL 的查询字符串中提供:In the following example, the [FromQuery] attribute indicates that the discontinuedOnly parameter value is provided in the request URL's query string:

[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] 属性将推理规则应用于操作参数的默认数据源。The [ApiController] attribute applies inference rules for the default data sources of action parameters. 借助这些规则,无需通过将属性应用于操作参数来手动识别绑定源。These rules save you from having to identify binding sources manually by applying attributes to the action parameters. 绑定源推理规则的行为如下:The binding source inference rules behave as follows:

  • [FromBody] 针对复杂类型参数进行推断。[FromBody] is inferred for complex type parameters. [FromBody] 不适用于具有特殊含义的任何复杂的内置类型,如 IFormCollectionCancellationTokenAn exception to the [FromBody] inference rule is any complex, built-in type with a special meaning, such as IFormCollection and CancellationToken. 绑定源推理代码将忽略这些特殊类型。The binding source inference code ignores those special types.
  • [FromForm] 针对 IFormFileIFormFileCollection 类型的操作参数进行推断。[FromForm] is inferred for action parameters of type IFormFile and IFormFileCollection. 该特性不针对任何简单类型或用户定义类型进行推断。It's not inferred for any simple or user-defined types.
  • [FromRoute] 针对与路由模板中的参数相匹配的任何操作参数名称进行推断。[FromRoute] is inferred for any action parameter name matching a parameter in the route template. 当多个路由与一个操作参数匹配时,任何路由值都视为 [FromRoute]When more than one route matches an action parameter, any route value is considered [FromRoute].
  • [FromQuery] 针对任何其他操作参数进行推断。[FromQuery] is inferred for any other action parameters.

FromBody 推理说明FromBody inference notes

对于简单类型(例如 stringint),推断不出 [FromBody][FromBody] isn't inferred for simple types such as string or int. 因此,如果需要该功能,对于简单类型,应使用 [FromBody] 属性。Therefore, the [FromBody] attribute should be used for simple types when that functionality is needed.

当操作拥有多个从请求正文中绑定的参数时,将会引发异常。When an action has more than one parameter bound from the request body, an exception is thrown. 例如,以下所有操作方法签名都会导致异常:For example, all of the following action method signatures cause an exception:

  • [FromBody] 对两者进行推断,因为它们是复杂类型。[FromBody] inferred on both because they're complex types.

    [HttpPost]
    public IActionResult Action1(Product product, Order order)
    
  • [FromBody] 对一个进行归属,对另一个进行推断,因为它是复杂类型。[FromBody] attribute on one, inferred on the other because it's a complex type.

    [HttpPost]
    public IActionResult Action2(Product product, [FromBody] Order order)
    
  • [FromBody] 对两者进行归属。[FromBody] attribute on both.

    [HttpPost]
    public IActionResult Action3([FromBody] Product product, [FromBody] Order order)
    

备注

在 ASP.NET Core 2.1 中,集合类型参数(如列表和数组)被不正确地推断为 [FromQuery]In ASP.NET Core 2.1, collection type parameters such as lists and arrays are incorrectly inferred as [FromQuery]. 若要从请求正文中绑定参数,应对这些参数使用 [FromBody] 属性。The [FromBody] attribute should be used for these parameters if they are to be bound from the request body. 此行为在 ASP.NET Core 2.2 或更高版本中得到了更正,其中集合类型参数默认被推断为从正文中绑定。This behavior is corrected in ASP.NET Core 2.2 or later, where collection type parameters are inferred to be bound from the body by default.

禁用推理规则Disable inference rules

若要禁用绑定源推理,请将 SuppressInferBindingSourcesForParameters 设置为 trueTo disable binding source inference, set SuppressInferBindingSourcesForParameters to true. Startup.ConfigureServices 中的 services.AddMvc().SetCompatibilityVersion 后添加下列代码:Add the following code in Startup.ConfigureServices after services.AddMvc().SetCompatibilityVersion:

services.AddMvc()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.SuppressUseValidationProblemDetailsForInvalidModelStateResponses = true;
        options.ClientErrorMapping[404].Link =
            "https://httpstatuses.com/404";
    });

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

使用 [FromForm] 属性批注操作参数时,[ApiController] 属性应用推理规则:将推断 multipart/form-data 请求内容类型。The [ApiController] attribute applies an inference rule when an action parameter is annotated with the [FromForm] attribute: the multipart/form-data request content type is inferred.

若要禁用默认行为,请在 Startup.ConfigureServices 中将 SuppressConsumesConstraintForFormFileParameters 设置为 true,如以下示例所示:To disable the default behavior, set SuppressConsumesConstraintForFormFileParameters to true in Startup.ConfigureServices, as shown in the following example:

services.AddMvc()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.SuppressUseValidationProblemDetailsForInvalidModelStateResponses = true;
        options.ClientErrorMapping[404].Link =
            "https://httpstatuses.com/404";
    });

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

当兼容性版本为 2.2 或更高版本时,MVC 会将错误结果(状态代码为 400 或更高的结果)转换为状态代码为 ProblemDetails 的结果。When the compatibility version is 2.2 or later, MVC transforms an error result (a result with status code 400 or higher) to a result with ProblemDetails. ProblemDetails 类型基于 RFC 7807 规范,用于提供 HTTP 响应中计算机可读的错误详细信息。The ProblemDetails type is based on the RFC 7807 specification for providing machine-readable error details in an HTTP response.

考虑在控制器操作中使用以下代码:Consider the following code in a controller action:

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

NotFound 的 HTTP 响应具有 404 状态代码和 ProblemDetails 正文。The HTTP response for NotFound has a 404 status code with a ProblemDetails body. 例如:For example:

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

自定义 ProblemDetails 响应Customize ProblemDetails response

使用 ClientErrorMapping 属性配置 ProblemDetails 响应的内容。Use the ClientErrorMapping property to configure the contents of the ProblemDetails response. 例如,以下代码会更新 404 响应的 type 属性:For example, the following code updates the type property for 404 responses:

services.AddMvc()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.SuppressUseValidationProblemDetailsForInvalidModelStateResponses = true;
        options.ClientErrorMapping[404].Link =
            "https://httpstatuses.com/404";
    });

禁用 ProblemDetails 响应Disable ProblemDetails response

SuppressMapClientErrors 属性设置为 true 时,会禁用 ProblemDetails 的自动创建。The automatic creation of ProblemDetails is disabled when the SuppressMapClientErrors property is set to true. Startup.ConfigureServices 中添加下列代码:Add the following code in Startup.ConfigureServices:

services.AddMvc()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.SuppressUseValidationProblemDetailsForInvalidModelStateResponses = true;
        options.ClientErrorMapping[404].Link =
            "https://httpstatuses.com/404";
    });

其他资源Additional resources