Search code examples
c#jsonbreeze

Deserializing DbGeometry with Newtonsoft.Json


I'm building a SPA using Angular,Breeze and Web API 2 following the approach as outlined by John Papa in his latest PluralSight course.

Everything works well and I can pull information, update, insert, delete back to the server. However I'm using Spatial Types, and when I try to update an entity with a spatial type I get the following error

An exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll but was not handled in user code

Additional information: Error getting value from 'WellKnownValue' on 'System.Data.Entity.Spatial.DbGeometry'.

The inner exception seems to point to the fact that the WellKnownValue is null, its not though, as I have checked the JSON being sent to the server which is then sent to the Breeze ContextProvider and saved using the SaveChanges method.

{
"entities": [
 {
  "TableKey": 2,
  "CaseName": "Mikhail Lermontov",
  "StartDate": "2013-06-11T00:00:00Z",
  "EndDate": null,
  "IsCurrent": true,
  "SRID": 109,
  "Shape": {
    "$id": "2",
    "$type": "System.Data.Entity.Spatial.DbGeometry, EntityFramework",
    "Geometry": {
      "$id": "3",
      "$type": "System.Data.Entity.Spatial.DbGeometryWellKnownValue, EntityFramework",
      "CoordinateSystemId": 2193,
      "WellKnownText": "POLYGON ((1695943 5462665, 1713098 5462665, 1713098 5449659, 1695943 5449659, 1695943 5462665))"
    }
  },
  "SpillLocation": "Marlborough Sounds",
  "Image": "http://www.nzmaritime.co.nz/images/lm5.jpg\r\n",
  "DefaultBaseMapKey": 2,
  "__unmapped": {
    "isPartial": false
  },
  "entityAspect": {
    "entityTypeName": "DatSpillCase:#Osiris.Model",
    "defaultResourceName": "DatSpillCases",
    "entityState": "Modified",
    "originalValuesMap": {
      "CaseName": "Mikhail Lermontov"
    },
    "autoGeneratedKey": {
      "propertyName": "TableKey",
      "autoGeneratedKeyType": "Identity"
    }
  }
}
 ],
  "saveOptions": {}
}

So my question is, is possible to deserialize DbGeometry types within the NewtonSoft library, and if not, what suggestions are there to get around that.


Solution

  • System.Data.Spatial.DbGeometry does not play nicely with Newtonsoft.Json

    You need to create a JsonConverter to convert the DbGeometry

    public class DbGeometryConverter : JsonConverter
        {
            public override bool CanConvert(Type objectType)
            {
                return objectType.IsAssignableFrom(typeof(string));
            }
    
            public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
            {
                JObject location = JObject.Load(reader);
                JToken token = location["Geometry"]["WellKnownText"];
                string value = token.ToString();
    
                DbGeometry converted = DbGeometry.PolygonFromText(value, 2193);
                return converted;
            }
    
            public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
            {
                // Base serialization is fine
                serializer.Serialize(writer, value);
            }
        }
    

    Then on your property in your model add the attribute

    [JsonConverter(typeof(DbGeometryConverter))]
    public DbGeometry Shape { get; set; }
    

    Now when you hit your BreezeController the deserialization will be handled by our new DbGeometryConverter.

    Hope it helps.