19

I am interested in adding support for partial updates in my ASP.NET Core WebAPI where I only update the properties on a resource that the caller provided, leaving excluded properties unchanged.

For context, imagine I have a resource that can be described as follows:

GET /users/1
{
    title: "Mister",
    firstName: "Frederick",
    middleName: "McFeely",
    lastName: "Rodgers"
}

If I wanted to allow consumers to change the value stored in the firstName property from "Frederick" to "Fred" in isolation, I should be able to expose a PATCH endpoint that supports the JSON Merge Patch Content-Type, like so:

PATCH /users/1
Content-Type: application/merge-patch+json
{
    firstName: "Fred"
}

However, I see no easy way for me to know that firstName is the only property being updated. For example, if I were to make a controller that accepted PATCH verbs, it could be scaffolded like this:

[Route("users")]
public class UsersController : Controller {

    [HttpPatch("{userId:int}")]
    public User Patch([FromRoute] int userId, [FromBody] User user) {

        // How do I know which properties were set on User at this point?

    }

}

public class User {

    public String Title { get; set; }
    public String FirstName { get; set; }
    public String MiddleName { get; set; }
    public String LastName { get; set; }

}

But I don't see how I can extract which properties' had keys defined on the JSON object before it was hydrated as a User and passed to my controller. I cannot assume a value of null to mean a property was excluded as the caller could be explicitly setting an optional property to null.

Edit

I am aware of the Microsoft.AspNetCore.JsonPatch library. This, unfortunately, expects the caller to use the "[description of changes]" to define a PATCH as described in RFC 5789, which I find unintuitive and verbose. I am referring to the "JSON Merge Patch" defined in RFC 7396.

5 Answers 5

7

I found a library that works: https://github.com/Morcatko/Morcatko.AspNetCore.JsonMergePatch

[HttpPatch]
[Consumes(JsonMergePatchDocument.ContentType)]
public void Patch([FromBody] JsonMergePatchDocument<Model> patch)
{
    ...
    patch.ApplyTo(backendModel);
    ...
}

Or use patch.JsonPatchDocument.Operations to walk through patch request fields manually.

Sign up to request clarification or add additional context in comments.

Comments

4

for simple types, I found a very simple solution using Newtonsoft.Json merge of JObjects:

public static T Patched<T>(T source, JObject patch) where T : class
{
    var sourceObject = JObject.FromObject(source);
    sourceObject.Merge(patch, new JsonMergeSettings() {MergeArrayHandling = MergeArrayHandling.Union});
    return sourceObject.ToObject<T>();
}

public static T Patched<T>(T source, string patchCode) where T : class
{
    return Patched<T>(source, JObject.Parse(patchCode));
}

Hope this helps someone searching for this topic and looking for a simple solution without external packages.

Comments

1

It appears like, for merge patch you will have to wait for odata support.

It is in beta at the moment and supports the merge semantics with the Delta<> class.

https://www.nuget.org/packages/Microsoft.AspNetCore.OData/

2 Comments

Nice, this looks really promising. I'll circle back on this when it's released.
There is some issues in 7.0.0 with entity ids and collections when deserializing the entity :(
-3

For doing a patch, you have to define PatchDocument.

More about it you can find PatchDocument

Example of method.

 [HttpPatch("{userId:int}")]   
 public IActionResult UserPatch(int userId, [FromBody] JsonPatchDocument<User> patchDocument) {

    var user = new User();
    // Because it comes from url.
    user.Id = userId;
    patchDocument.ApplyTo(user);

    // Here you call context or repository to save.

  }

Example of document.

[
  { "op": "replace", "path": "/firstName", "value": "boo" },
]

That will update firstName field to 'boo' in user model.

1 Comment

Hi, thanks for answering. Unfortunately, you are confusing the original idea of PATCH with what I am looking for: the JSON Merge PATCH. These use the same verb, but the latter is a specific content type as defined in the RFC.
-3

What you might be looking for is ASP.Net Core JsonPatchDocument

https://github.com/aspnet/JsonPatch

https://learn.microsoft.com/en-us/aspnet/core/api/microsoft.aspnetcore.jsonpatch

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.