Search code examples
c#restasp.net-web-apipatchmodelstate

ModelState remains valid during Json Patch


I am builing an Api using the JsonPatch Document described here:

JsonPatch in ASP.NET Core web API

I have the following method in my controller:

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

And the following DTO:

public record ClientDto
{
    public int? Id { get; set; }

    [Required]
    [StringLength(50, MinimumLength = 1)]
    public required string Name { get; set; }
}

When testing my implementation, I am expecting the following PATCH request to result in an invalid Model and therefore a 400 response:

[
  {
    "path": "/name",
    "op": "replace",
    "value": "Changed"
  }
]

However, during testing, the ModelState remains Valid when sending the above Patch. Can anyone advise what I am doing wrong?


Solution

  • There is the ControllerBase.TryValidateModel(object) method that can be called once the changes have been applied to the model:

    clientPatch.ApplyTo(clientDto, ModelState);
                
    if(Model.IsValid && TryValidateModel(clientDto))
    {
        // Logic when valid
    
        return NoContent();
    }
    
    return ValidationProblem(ModelState);
    

    If the model validation fails, returning theControllerBase.ValidationProblem(ModelStateDictionary) method will also ensure the response is consistant with the default middleware validation when using Data Annotations.