ASP.NET Core JsonPatch中ModelState始终有效问题求助
问题描述
我正在使用ASP.NET Core的JsonPatch Document构建API,控制器中的Patch方法如下:
[HttpPatch("{id:int}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task<ActionResult> Patch(int id, [FromBody] JsonPatchDocument<ClientDto> clientPatch) { Client? client = await _clientRepository.GetClientAsync(id); if (client != null) { ClientDto clientDto = _mapper.Map<ClientDto>(client); clientPatch.ApplyTo(clientDto, ModelState); if(ModelState.IsValid) { _mapper.Map(clientDto, client); await _clientRepository.UpdateClientAsync(client); return NoContent(); } return BadRequest(); } return NotFound(); }
对应的DTO定义:
public record ClientDto { public int? Id { get; set; } [Required] [StringLength(50, MinimumLength = 1)] public required string Name { get; set; } }
我原本以为发送如下PATCH请求会触发Model验证失败,返回400响应:
[ { "path": "/name", "op": "replace", "value": "Changed" } ]
但实际测试时,ModelState始终显示有效,请问哪里操作有误?
解决方法
问题出在JsonPatchDocument.ApplyTo方法的行为上:
- 该方法仅会捕获JsonPatch操作本身的错误(比如路径不存在、操作类型无效等),不会自动验证DTO上标注的数据注解(如
[Required]、[StringLength])。 - 你测试的请求是合法的替换操作,所以
ModelState不会被标记为无效。
要触发DTO的属性验证,需要在ApplyTo之后手动验证clientDto,并将验证结果合并到ModelState中。修改后的代码如下:
[HttpPatch("{id:int}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task<ActionResult> Patch(int id, [FromBody] JsonPatchDocument<ClientDto> clientPatch) { Client? client = await _clientRepository.GetClientAsync(id); if (client != null) { ClientDto clientDto = _mapper.Map<ClientDto>(client); clientPatch.ApplyTo(clientDto, ModelState); // 新增:手动验证DTO的属性规则 if (!TryValidateModel(clientDto)) { return BadRequest(ModelState); } if(ModelState.IsValid) { _mapper.Map(clientDto, client); await _clientRepository.UpdateClientAsync(client); return NoContent(); } return BadRequest(); } return NotFound(); }
现在如果发送违反DTO验证规则的请求(比如将value设为空字符串),TryValidateModel会触发数据注解验证,将错误写入ModelState,最终返回400响应。
内容的提问来源于stack exchange,提问作者Andy Clark
相关产品推荐
相关产品推荐

