JSON.NET deserialialization issues with embeded objects.

May 18, 2014 at 4:56 AM
I have a bizzare problem in that the JSOn Deserialization within my WebAPO 2.1 code does not appear to be working correctly in all cases.

When I have simple objects, and objects with all of the data filled out, it works correctly, however, if any of my embedded objects are null as being sent over from the browser via jQuery's ajax call, things go wrong.

In the example below, the EntityId property of the object (found in the base class) gets placed in the PreferredSpecialty property in the derived class, the base class's property is null, and the preferred Species is null. The preferredLocallity is filled out as expected.


I downloaded the JSON.NET source code, and built several tests using the same JSON.Net version directy in various calls, and I have not been able to replicate the results outside of the WebAPI call.

Here is my question:

Does anyone see what could be wrong with the code (below), or know/have a sample snippet of test code that would mimic how the ASP.NET Web API 2.1 would call into the JSON.Net library do do the deserialization?


I have a some javascript code that calls a WebAPI 2.1 method with the footprint of this:
    [Route("api/Reservation/{Id}")]
    public object Put(int Id, [FromBody] Reservation model)
The json being sent over (via JQuery is this):
{
"confirmationNumber":"Test_Value",
"requiresHandicapAccessible":false,
"totalIndividuals":1,
"adultIndividuals":1,
"seniorIndividuals":0,
"childIndividuals":0,
"comments":"",
"totalPrice":225,
"preferredLocality":{"id":1469,"pid":"PR"},
"preferredSpecies":null,
"preferredSpecialty":null,
"entityId":{"id":1035,"pid":"PR"},
}
The C# classes that represent this data is as follows:
public class EntityId
{
    public int Id { get; set; }
    public string PID { get; set; }
}

public class DataObjectBASE : EntityBASE
{
    public EntityId EntityId { get; set; }
    public ObjectDetails Details { get; set; }
}

public class Reservation : DataObjectBASE
{
    public string ConfirmationNumber { get; set; }
    public bool? RequiresHandicapAccessible { get; set; }
    public int TotalIndividuals { get; set; }
    public int AdultIndividuals { get; set; }
    public int SeniorIndividuals { get; set; }
    public int ChildIndividuals { get; set; }
    public string Comments { get; set; }
    public decimal TotalPrice { get; set; }
    public EntityId PreferredLocality { get; set; }
    public EntityId PreferredSpecies { get; set; }
    public EntityId PreferredSpecialty { get; set; }
}
I was unable to get anything like this working without writing a custom JSONConverter for EntityId (shown below):
  public class EntityIdConverter : JsonConverter
  {
    public override bool CanConvert(Type objectType)
    {
      return objectType.Equals(typeof(EntityId));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        int? iId = null;
        string strPID = string.Empty;

        while(reader.TokenType != JsonToken.EndObject)
        {
          //-- Read a Property...
          reader.Read();
          if(reader.TokenType == JsonToken.PropertyName)
          {
            string strPropertyName = DataUtilities.ObjectAsString(reader.Value);

            //-- Read the value
            if(strPropertyName.Equals("id", StringComparison.OrdinalIgnoreCase))
            {
              iId = reader.ReadAsInt32();
            }
            else
            {
              if(strPropertyName.Equals("pid", StringComparison.OrdinalIgnoreCase))
              {
                strPID = reader.ReadAsString();
              }
              else
              {
                // Unexpected property, ignore it...
                reader.Read();
              }
            }
          }
        }

        if(iId != null)
        {
          return new EntityId(iId.Value, strPID);
        }
        else
        {
          return null;
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
      var model = value as EntityId;
      if(model != null)
      {
        writer.WriteStartObject();

        writer.WritePropertyName("id");
        writer.WriteValue(model.Id);

        writer.WritePropertyName("pid");
        writer.WriteValue(model.PID);

        writer.WriteEndObject();
      }
      else
      {
        writer.WriteNull();
      }
    }
  }
Thanks, any ideas or pointers would be greatly appreciated!

John