ASP.NET 核心模型绑定行为切换

ASP.NET Core model binding behaviour switch

在 API 的一些重大重构过程中,我似乎更改了一些影响模型绑定/模型验证行为的东西。

我试图调查这些变化,但我无法弄清楚变化的原因。

我有一个 MyApiController 继承自 ControllerBaseMyApiController 有一个 post 方法接收请求模型(使用默认 API 模板创建,没有 HTTPS 给你典型的 ValuesController)。

  using Microsoft.AspNetCore.Mvc;
  using Microsoft.Extensions.Logging;
  using Newtonsoft.Json;
  using System;
  using System.Threading.Tasks;

  namespace XperimentModelBinding.Controllers
  {

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

      public ILogger<MyApiController> Logger { get; }

      public MyApiController(ILogger<MyApiController> logger)
      {
        Logger = logger ?? throw new ArgumentNullException(nameof(logger));
      }


      [HttpPost()]
      public async Task<IActionResult> PostModel([FromBody] MyCreateRequestModel request)
      {

        Logger.LogInformation("PostModel: " + JsonConvert.SerializeObject(request, Formatting.None));

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

        return Ok();

      }
    }
  }

我使用的模型是:

  using System.ComponentModel.DataAnnotations;

  namespace XperimentModelBinding
  {

    public class MyCreateRequestModel
    {

      [Required]
      [StringLength(10)]
      public string Name { get; set; }

      [Required]
      [Range(1, 5)]
      public int Value { get; set; }

    }

  }

启动它并在记录器上设置断点。

与post人一起测试:

测试 1:

  {
    "Name": "1234567890",
    "Value": 1
  }

遇到断点,returns 200 OK(如预期)。

测试 2:

  {
    "Name": null,
    "Value": 1
  }

断点未命中,返回的模型为:

  {
    "errors": {
        "Name": [
            "The Name field is required."
        ]
    },
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "80000006-0000-ff00-b63f-84710c7967bb"
  }

预期的结果是调用该方法,命中换行符,到目前为止我有响应模型(似乎只包含错误):

{
    "Name": [
        "The Name field is required."
    ]
}

改变的是:给定一个无效模型的请求,我的方法被调用,我检查 ModelState.IsValid 是否有错误。这很棒,因为我以这种方式创建了我的自定义响应模型。

现在我的方法不再被调用,模型直接绑定 returns 自己的模型。

我的方法不再被调用有什么变化?

它连接到 link

的 [ApiController] 属性

Web API controllers don't have to check ModelState.IsValid if they have the > [ApiController] attribute. In that case, an automatic HTTP 400 response containing issue details is returned when model state is invalid. For more information, see Automatic HTTP 400 responses.

您可能想在 Startup.cs 中的 services.AddMvc() 中使用 ConfigureApiBehaviorOptions 来设置针对无效模型请求的自定义错误消息。

services.AddMvc()
    .ConfigureApiBehaviorOptions(options => {
        options.InvalidModelStateResponseFactory = actionContext =>
        {
            var modelState = actionContext.ModelState.Values;
            return new BadRequestObjectResult(new ErrorResult(modelState));
        };
    });
});

并根据需要定义 ErrorResult class,例如:

public class ErrorResult
{
    public int code { get; set; }
    public string message { get; set; }

    public ErrorResult()
    {
    }

    public ErrorResult(ModelStateDictionary.ValueEnumerable modelState)
    {
        // This will take the error message coming directly from modelState
        foreach (var value in modelState)
        {
            if (value.Errors.Count > 0)
            {
                code = 900; // Or use a code handler or whatever
                message = value.Errors.FirstOrDefault().ErrorMessage;
                break;
            }
        }
    }
}