This issue affects my ASP.Net WebApi patch method, which looks something like this:
public MyModel Patch(int id, [FromBody]Delta<MyModel> newRecord){}
But it is not WebApi that the problem is the failure between Json.Net and OData.Delta.
Problem JsonConvert.DeserializeObject does not see integers of OData.Delta strong> objects, and I am wondering if there is a workaround or fix that I can apply.
UPDATE: wrote code (see below) in the Json.Net library that will fix this. It just needs to be included in the next update (if James Newton King allows)
UPDATE 2: after further testing, I decided that the best way to do this is to stop using OData.Delta and write my own (see answer)
Units tests to prove the problem exist (using the instructions below for clarity)
Test 1: crashing with int (Int32):
class TestObjWithInt { public int Int { get; set; } } [TestMethod] public void IsApplied_When_IntIsDeserializedToDelta() { string testData = "{\"Int\":1}"; var deserializedDelta = JsonConvert.DeserializeObject<Delta<TestObjWithInt>>(testData); var result = deserializedDelta.GetChangedPropertyNames().Contains("Int"); Assert.IsTrue(result); }
Test 2: succeeds with long (Int64)
class TestObjWithLong { public long Long { get; set; } } [TestMethod] public void IsApplied_When_LongIsDeserializedToDelta() { string testData = "{\"Long\":1}"; var deserializedDelta = JsonConvert.DeserializeObject<Delta<TestObjWithLong>>(testData); var result = deserializedDelta.GetChangedPropertyNames().Contains("Long"); Assert.IsTrue(result); }
And to be sure that deserialization works for starters, these two tests pass.
[TestMethod] public void IsApplied_When_LongIsDeserializedToTestObject() { string testData = "{\"Long\":1}"; var deserializedObject = JsonConvert.DeserializeObject<TestObjWithLong>(testData); var result = deserializedObject.Long == 1; Assert.IsTrue(result); } [TestMethod] public void IsApplied_When_IntIsDeserializedToTestObject() { string testData = "{\"Int\":1}"; var deserializedObject = JsonConvert.DeserializeObject<TestObjWithInt>(testData); var result = deserializedObject.Int == 1; Assert.IsTrue(result); }
I found this OData Error Report, which looks like a similar problem, but its old and closed, so probably not.
Any help would be great.
Using statements (from the top of the test file):
using System; using System.Linq; using System.Web.Http.OData; using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json;
The decision made by James Newton King - will change to release 6.0.6. Replace the line J81SerializerInternalReader.cs 1581:
contract.TrySetMember(newObject, memberName, value);
from:
bool done = false; while (!(done = done || contract.TrySetMember(newObject, memberName, value))) { switch (reader.TokenType) { case JsonToken.Integer: if (value is long && ((long)value) <= Int32.MaxValue && ((long)value) >= Int32.MinValue) value = Convert.ToInt32(value);