0

I'm trying to send an AJAX PATCH request to a Web API method and have the patched object recognised by Marvin.JsonPatch.

So far, everything I've sent to the server has resulted in an empty request being received.

The Web API controller method looks like this:

public async Task<IHttpActionResult> Update(long orderId, JsonPatchDocument<Order> patchedOrder)

I'm POSTing using an HttpClient like this (can't use async in this application)...

var patchDoc = new JsonPatchDocument<Order>();
patchDoc.Replace(e => e.Price, newPrice);
patchDoc.Replace(e => e.WordCount, newWordCount);

var request = new HttpRequestMessage(new HttpMethod("PATCH"), uri)
              {
                  Content = new StringContent(JsonConvert.SerializeObject(patchDoc),
                                              System.Text.Encoding.Unicode,
                                              "application/json")
              };

HttpResponseMessage response;
using (var client = new HttpClient(...))
{
    response = client.SendAsync(request).GetAwaiter().GetResult();
}

But when the controller is it, the patchedOrder argument is null.

While debugging on the controller I've also tried

var s = await Request.Content.ReadAsStringAsync();

But this returns an empty string - can anyone explain why?

UPDATE:
This is what the contents of the JsonPatch document look like when passed in to the HttpClient...

{
    "Operations": [{
        "OperationType": 2,
        "value": 138.7,
        "path": "/price",
        "op": "replace"
    },
    {
        "OperationType": 2,
        "value": 1320,
        "path": "/wordcount",
        "op": "replace"
    }],
    "ContractResolver": {
        "DynamicCodeGeneration": true,
        "DefaultMembersSearchFlags": 20,
        "SerializeCompilerGeneratedMembers": false,
        "IgnoreSerializableInterface": false,
        "IgnoreSerializableAttribute": true,
        "NamingStrategy": null
    },
    "CaseTransformType": 0
}
awj
  • 7,482
  • 10
  • 66
  • 120
  • 1
    Does `JsonConvert.SerializeObject(patchDoc)` look like a JSON patch document? – CodeCaster Sep 26 '18 at 12:14
  • @CodeCaster I've added the serialized content to the OP. – awj Sep 26 '18 at 12:42
  • Well that's not good. Update your packages (at least Marvin.JsonPatch and Newtonsoft.Json) to the latest versions. There should be a custom serializer on the `JsonPatchDocument` which writes only the operations, not the entire object. – CodeCaster Sep 26 '18 at 12:44
  • I _was_ using Marvin.JsonPatch v2.1 but this had the same problem, so I downgraded to v1.1 as this is what is referenced in the WebAPI project, but obviously the problem persisted. Now that I've reverted to v2.1 it's still there but I can call `JsonConvert.SerializeObject(patchDoc.Operations)` and this works. If you put your last comment as an answer then I'll mark as accepted. – awj Sep 26 '18 at 13:11

1 Answers1

1

Somewhere during the development of Marvin.JsonPatch, the JsonPatchDocument<T> was annotated with an attribute that applied a custom JSON serializer:

[JsonConverter(typeof(JsonPatchDocumentConverter))]

This converter enables you to call JsonConvert.SerializeObject() on such a patch document and actually generate a patch document, as opposed to a representation of the JsonPatchDocument<T> CLR object.

Upgrade Marvin.JsonPatch and Newtonsoft.Json to the latest verison, and serialization should succeed.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • This didn't work for me - I decorated the `Order` object with that `JsonConverter` attribute but I still receive `null`. It looks like that custom serializer produces an object with an 'Operations' property (which contains an array of operations), _i.e._ `{"Operations":[{"OperationType":2, ...` , whereas what works for me is serializing simply the operations themselves, _i.e._, `JsonConvert.Serialize(patchDoc.Operations)`. – awj Sep 26 '18 at 13:41
  • My point is that with the latest Marvin.JsonPatch, your `JsonConvert.SerializeObject(patchDoc)` should internally serialize only `patchDoc.Operations`... If it doesn't, then something else is amiss. – CodeCaster Sep 26 '18 at 13:43