Search code examples
c#asp.net-corepostmanjson-patch

Why is my PATCH request empty in an ASP.NET Controller?


I have the following ASP.net Core Controller:

[ApiVersion(ApiConstants.Versions.V1)]
[Route(RouteConstants.ApiControllerPrefix + "/tenants/" + RouteConstants.TenantIdRegex + "/entities")]
public class EntityController
{
    [HttpPatch]
    [SwaggerOperation(OperationId = nameof(PatchEntity))]
    [Route("{controlId:guid}", Name = nameof(PatchEntity))]
    [SwaggerResponse(StatusCodes.Status204NoContent, "Result of the patch")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [Consumes(MediaTypes.Application.JsonPatch)]
    public async Task<IActionResult> PatchEntity(string tenantId, Guid entityId, JsonPatchDocument<EntityModel> entityPatches)
    {
        //
    }
}

The controller allows me to patch an existing entity. Here is the model:

[JsonObject(MemberSerialization.OptIn)]
public class EntityModel
{
    [JsonProperty(PropertyName = "isAuthorized")]
    public bool IsAuthorized { get; set; }
}

For my test, I am using postman to send a patch on an entity. I selected the verb PATCH targeted to this URL:

http://localhost:5012/api/v1/tenants/tenant-id/entities/01111111-0D1C-44D6-ABC4-2C9961F94905

In the headers, I added the Content-Type entry and set it to application/json-patch+json.

Here is the body of the request:

[
    { "op": "replace", "path": "/isAuthorized", "value": "false" }
]

I started the application and set a breakpoint on the controller. The breakpoint is hit, with the proper tenant ID and entity ID. However, the entityPatches does not have any operations:

entityPatches.Operations.Count = 0

Consequently, the property IsAuthorized of the targeted EntityModel can't be updated. I would have expected the Operations property to have one replace operation, as defined in the HTTP request.

Question

Why is the Operations property of the JsonPatchDocument class missing the patch operations defined in the body of the HTTP request?


Solution

  • You are missing the FromBody attribute on the entityPatches parameter, for example:

    public async Task<IActionResult> PatchEntity(
        string tenantId, 
        Guid entityId, 
        [FromBody] JsonPatchDocument<EntityModel> entityPatches)
      //^^^^^^^^^^ Add this
    {
        //snip
    }