相关文章推荐
路过的帽子  ·  .Net ...·  昨天    · 
暗恋学妹的投影仪  ·  Android ...·  6 月前    · 
玉树临风的弓箭  ·  Add new item to ...·  1 年前    · 

ASP.NET Core 支持使用控制器或使用最少的 API 创建 Web API。 Web API 中的 控制器 是派生自 ControllerBase 的类。 控制器按请求激活和释放。

本文介绍了如何使用控制器处理 Web API 请求。 有关在没有控制器的情况下创建 Web API 的信息,请参阅 教程:使用 ASP.NET Core 创建最小 API

ControllerBase 类

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

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

Web API 控制器通常应派生自 ControllerBase 而不是 ControllerController 派生自 ControllerBase,并添加对视图的支持,因此它用于处理 Web 页面,而不是 Web API 请求。 如果同一控制器必须支持视图和 Web 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 中的方法示例。

有关可用方法和属性的列表,请参阅 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);

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

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

ApiController 属性

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

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

    [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
    

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

    自动 HTTP 400 响应

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

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

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

    默认 BadRequest 响应

    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 方法,而不是 BadRequestValidationProblem 返回 ValidationProblemDetails 对象以及自动响应。

    记录自动 400 响应

    若要记录自动 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();
    

    禁用自动 400 响应

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

    绑定源参数推理

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

    当值可能包含 %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();
            products = _productsInMemoryStore;
        return products;
    

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

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

    对于简单类型(例如 stringint),推断不出 [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)
    

    FromServices 推理说明

    当类型配置为服务时,参数绑定通过依赖关系注入绑定参数。 这意味着不需要将 [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);
    

    在极少数情况下,自动 DI 可能会中断 DI 中具有 API 控制器的操作方法中也接受的类型的应用。 在 DI 中拥有类型并作为 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 控制器操作中的参数是来自 DI 还是来自其他源。

    用于推断 API 控制器操作参数绑定源的机制使用以下规则:

  • 以前指定的 BindingInfo.BindingSource 永远不会被覆盖。
  • 在 DI 容器中注册的复杂类型参数被分配 BindingSource.Services
  • 在 DI 容器中未注册的复杂类型参数被分配 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();
    

    Multipart/form-data 请求推理

    [ApiController] 属性对 IFormFileIFormFileCollection 类型的操作参数应用推理规则。 为这些类型推断 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 方法会生成带 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。 添加以下代码:

    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();
    

    使用 [Consumes] 属性定义支持的请求内容类型

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

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

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

    在上面的代码中,CreateProduct 操作指定内容类型 application/xml。 路由到此操作的请求必须指定 application/xmlContent-Type 头。 如果请求未指定 application/xmlContent-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 的请求。 控制器的两个操作(PostJsonPostForm)都使用相同的 URL 处理 POST 请求。 如果 [Consumes] 属性不应用类型约束,则会抛出不明确匹配异常。

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

  • 查看或下载示例代码。 (下载方法)。
  • ASP.NET Core Web API 中控制器操作的返回类型
  • 处理 ASP.NET Core Web API 中的错误
  • ASP.NET Core Web API 中的自定义格式化程序
  • 设置 ASP.NET Core Web API 中响应数据的格式
  • 带有 Swagger/OpenAPI 的 ASP.NET Core Web API 文档
  • 在 ASP.NET Core 中路由到控制器操作
  • 使用端口隧道 Visual Studio 调试 Web API
  • 使用 ASP.NET Core 创建 Web API
  • ASP.NET Core 支持使用控制器或使用最少的 API 创建 Web API。 Web API 中的控制器是派生自 ControllerBase 的类。 本文介绍了如何使用控制器处理 Web API 请求。 有关在没有控制器的情况下创建 Web API 的信息,请参阅教程:使用 ASP.NET Core 创建最小 API

    ControllerBase 类

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

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

    Web API 控制器通常应派生自 ControllerBase 而不是 ControllerController 派生自 ControllerBase,并添加对视图的支持,因此它用于处理 Web 页面,而不是 Web API 请求。 如果同一控制器必须支持视图和 Web 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 中的方法示例。

    有关可用方法和属性的列表,请参阅 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);
    

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

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

    ApiController 属性

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

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

    [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
    

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

    自动 HTTP 400 响应

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

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

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

    默认 BadRequest 响应

    下述响应正文是序列化类型的示例:

    "": [ "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 类型:

  • 提供计算机可读的格式来指定 Web API 响应中的错误。
  • 符合 RFC 7807 规范
  • 要使自动和自定义响应保持一致,请调用 ValidationProblem 方法,而不是 BadRequestValidationProblem 返回 ValidationProblemDetails 对象以及自动响应。

    记录自动 400 响应

    若要记录自动 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();
    

    禁用自动 400 响应

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

    绑定源参数推理

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

    当值可能包含 %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();
            products = _productsInMemoryStore;
        return products;
    

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

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

    对于简单类型(例如 stringint),推断不出 [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)
    

    禁用推理规则

    若要禁用绑定源推理,请将 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();
    

    Multipart/form-data 请求推理

    [ApiController] 属性对 IFormFileIFormFileCollection 类型的操作参数应用推理规则。 为这些类型推断 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 方法会生成带 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

    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();
    

    使用 [Consumes] 属性定义支持的请求内容类型

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

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

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

    在上面的代码中,CreateProduct 操作指定内容类型 application/xml。 路由到此操作的请求必须指定 application/xmlContent-Type 头。 如果请求未指定 application/xmlContent-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 的请求。 控制器的两个操作(PostJsonPostForm)都使用相同的 URL 处理 POST 请求。 如果 [Consumes] 属性不应用类型约束,则会抛出不明确匹配异常。

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

  • 查看或下载示例代码。 (下载方法)。
  • ASP.NET Core Web API 中控制器操作的返回类型
  • 处理 ASP.NET Core Web API 中的错误
  • ASP.NET Core Web API 中的自定义格式化程序
  • 设置 ASP.NET Core Web API 中响应数据的格式
  • 带有 Swagger/OpenAPI 的 ASP.NET Core Web API 文档
  • 在 ASP.NET Core 中路由到控制器操作
  • 使用端口隧道 Visual Studio 调试 Web API
  • 使用 ASP.NET Core 创建 Web API
  • 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
    

    不要通过从 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 提供的方法的更多示例。

    有关可用方法和属性的列表,请参阅 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);
    

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

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

    ApiController 属性

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

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

    [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] 属性可应用于程序集。 以这种方式进行注释,会将 web API 行为应用到程序集中的所有控制器。 无法针对单个控制器执行选择退出操作。 将程序集级别的属性应用于 Startup 类两侧的命名空间声明:

    [assembly: ApiController]
    namespace WebApiSample
        public class Startup
    

    特性路由要求

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

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

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

    自动 HTTP 400 响应

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

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

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

    默认 BadRequest 响应

    下述请求正文是序列化类型的示例:

    "": [ "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 类型:

  • 提供计算机可读的格式来指定 Web API 响应中的错误。
  • 符合 RFC 7807 规范
  • 要使自动和自定义响应保持一致,请调用 ValidationProblem 方法,而不是 BadRequestValidationProblem 返回 ValidationProblemDetails 对象以及自动响应。

    记录自动 400 响应

    若要记录自动 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);
    

    禁用自动 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";
            options.DisableImplicitFromServicesParameters = true;
    

    绑定源参数推理

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

    当值可能包含 %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();
            products = _productsInMemoryStore;
        return products;
    

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

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

    对于简单类型(例如 stringint),推断不出 [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)
    

    禁用推理规则

    若要禁用绑定源推理,请将 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;
    

    Multipart/form-data 请求推理

    [ApiController] 属性对 IFormFileIFormFileCollection 类型的操作参数应用推理规则。 为这些类型推断 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";
            options.DisableImplicitFromServicesParameters = true;
    

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

    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[StatusCodes.Status404NotFound].Link =
                "https://httpstatuses.com/404";
            options.DisableImplicitFromServicesParameters = true;
    

    使用 [Consumes] 属性定义支持的请求内容类型

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

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

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

    在上面的代码中,CreateProduct 操作指定内容类型 application/xml。 路由到此操作的请求必须指定 application/xmlContent-Type 头。 如果请求未指定 application/xmlContent-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 的请求。 控制器的两个操作(PostJsonPostForm)都使用相同的 URL 处理 POST 请求。 如果 [Consumes] 属性不应用类型约束,则会抛出不明确匹配异常。

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

  • ASP.NET Core Web API 中控制器操作的返回类型
  • 处理 ASP.NET Core Web API 中的错误
  • ASP.NET Core Web API 中的自定义格式化程序
  • 设置 ASP.NET Core Web API 中响应数据的格式
  • 带有 Swagger/OpenAPI 的 ASP.NET Core Web API 文档
  • 在 ASP.NET Core 中路由到控制器操作
  • 使用 ASP.NET Core 创建 Web API
  • [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 提供的方法的更多示例:

    有关可用方法和属性的列表,请参阅 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);
    

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

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

    ApiController 属性

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

  • 属性路由要求
  • 自动 HTTP 400 响应
  • 绑定源参数推理
  • Multipart/form-data 请求推理
  • 错误状态代码的问题详细信息必须有兼容性版本 2.2 或更高版本,才能使用“错误状态代码的问题详细信息”功能。 必须有兼容性版本 2.1 或更高版本,才能使用其他功能。
  • 属性路由要求
  • 自动 HTTP 400 响应
  • 绑定源参数推理
  • Multipart/form-data 请求推理这些功能需要兼容性版本为 2.1 或更高版本。
  • 特定控制器上的属性

    [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] 属性可应用于程序集。 以这种方式进行注释,会将 web API 行为应用到程序集中的所有控制器。 无法针对单个控制器执行选择退出操作。 将程序集级别的属性应用于 Startup 类两侧的命名空间声明:

    [assembly: ApiController]
    namespace WebApiSample
        public class Startup
    

    特性路由要求

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

    [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 规范
  • 要使自动和自定义响应保持一致,请调用 ValidationProblem 方法,而不是 BadRequestValidationProblem 返回 ValidationProblemDetails 对象以及自动响应。

    记录自动 400 响应

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

    禁用自动 400 响应

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

    services.Configure<ApiBehaviorOptions>(options =>
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
    

    绑定源参数推理

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

    当值可能包含 %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();
            products = _productsInMemoryStore;
        return products;
    

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

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

    对于简单类型(例如 stringint),推断不出 [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.Configure<ApiBehaviorOptions>(options =>
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
    

    Multipart/form-data 请求推理

    [ApiController] 属性对 IFormFileIFormFileCollection 类型的操作参数应用推理规则。 为这些类型推断 multipart/form-data 请求内容类型。 要禁用默认行为,请在 Startup.ConfigureServices 中将 SuppressConsumesConstraintForFormFileParameters 属性设置为 true

    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 中添加下列代码:

    使用 [Consumes] 属性定义支持的请求内容类型

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

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

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

    在上面的代码中,CreateProduct 操作指定内容类型 application/xml。 路由到此操作的请求必须指定 application/xmlContent-Type 头。 如果请求未指定 application/xmlContent-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 的请求。 控制器的两个操作(PostJsonPostForm)都使用相同的 URL 处理 POST 请求。 如果 [Consumes] 属性不应用类型约束,则会抛出不明确匹配异常。 [Consumes] 属性应用于两个操作。 PostJson 操作处理使用 application/jsonContent-Type 头发送的请求。 PostForm 操作处理使用 application/x-www-form-urlencodedContent-Type 头发送的请求。

  • ASP.NET Core Web API 中控制器操作的返回类型
  • 处理 ASP.NET Core Web API 中的错误
  • ASP.NET Core Web API 中的自定义格式化程序
  • 设置 ASP.NET Core Web API 中响应数据的格式
  • 带有 Swagger/OpenAPI 的 ASP.NET Core Web API 文档
  • 在 ASP.NET Core 中路由到控制器操作
  • 使用 ASP.NET Core 创建 Web API
  •