6

I am trying to get Spartial Data from a Database and then Serialize it (working great). When I try to deserialize that Data a JsonSerializationException is thrown.

DbGeography geoPoint = CreatePoint(40.7056308, -73.9780035);
string serializedPoint = JsonConvert.SerializeObject(geoPoint);
DbGeography resjson = JsonConvert.DeserializeObject<DbGeography>(serializedPoint);

Here is the CreatePoint Method:

public static DbGeography CreatePoint(double latitude, double longitude)
{
string text = string.Format(CultureInfo.InvariantCulture.NumberFormat,
"POINT({0} {1})", longitude, latitude);
return DbGeography.PointFromText(text, 4326);
}

I produced this Error in a Console Application.

Nuget Packages installed: 
EntityFramework 6.1.0
Newtonsoft.Json 6.0.3

Does anybody know what I am doing wrong?

gunr2171
  • 16,104
  • 25
  • 61
  • 88
Alex Doe
  • 300
  • 2
  • 8
  • 2
    Take a moment to read through the [edit help](http://stackoverflow.com/editing-help). Your original question was one wall of text, and your code was hidden. Formatting in [SO] is different that other sites. – gunr2171 May 21 '14 at 17:53
  • 1
    And what is the message when you get *JsonSerializationException* ? – L.B May 21 '14 at 18:02

1 Answers1

12

System.Data.Spatial.DbGeography (which I assume you are using) is not suitable for deserialization by Newtonsoft.Json. You do not mention the thrown exception, but the one I observe is:

Unable to find a constructor to use for type System.Data.Spatial.DbGeography. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute.

You can resolve this by providing the serialization/deserialization logic yourself by means of a JsonConverter. I've used the one from JSON.Net JsonConverter for DbGeography and slightly modified it to fix a bug for my local culture (which uses ',' as the decimal separator):

public class DbGeographyConverter : JsonConverter
{
    private const string LATITUDE_KEY = "latitude";
    private const string LONGITUDE_KEY = "longitude";

    public override bool CanConvert(Type objectType)
    {
        return objectType.Equals(typeof(DbGeography));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return default(DbGeography);

        var jObject = JObject.Load(reader);

        if (!jObject.HasValues || (jObject.Property(LATITUDE_KEY) == null || jObject.Property(LONGITUDE_KEY) == null))
            return default(DbGeography);

        string wkt = string.Format(CultureInfo.InvariantCulture, "POINT({1} {0})", jObject[LATITUDE_KEY], jObject[LONGITUDE_KEY]);
        return DbGeography.FromText(wkt, DbGeography.DefaultCoordinateSystemId);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var dbGeography = value as DbGeography;

        serializer.Serialize(writer, dbGeography == null || dbGeography.IsEmpty ? null : new { latitude = dbGeography.Latitude.Value, longitude = dbGeography.Longitude.Value });
    }
}

You can then use it like this:

DbGeography geoPoint = CreatePoint(40.7056308, -73.9780035);
string serializedPoint = JsonConvert.SerializeObject(geoPoint, new DbGeographyConverter());
DbGeography resjson = JsonConvert.DeserializeObject<DbGeography>(serializedPoint, new DbGeographyConverter());
Community
  • 1
  • 1
TC.
  • 4,133
  • 3
  • 31
  • 33