Search code examples
c#jsonjson.netgeojson

Newtonsoft.Json.JsonWriterException with GeoJson


I am trying to return a List Of GeoPoints in a asp.net mvc controller.

The Points & Feature classes are part of the Geojson.net library.

public async Task<ActionResult> GetGeoData()
{     
    var query = _db.Data_Raw
      .Where(x => x.Geography != null);      
    var dbResults = await query.Take(100).ToListAsync();

    var points = new List<Feature>();
    foreach (var item in dbResults)
    {
        var point = new Point(new Position(item.Geography.Longitude.Value, item.Geography.Latitude.Value, item.Altitude));
        var featureProperties = new Dictionary<string, object> { { "Speed", item.Speed }, { "Bearing", item.Course } };
        points.Add(new Feature(point, featureProperties));
    }

    var model = new MultiPoint(new List<Point>());

    var serializedData = JsonConvert.SerializeObject(model, Formatting.Indented,
        new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver(),
            NullValueHandling = NullValueHandling.Ignore
        });

    return Content(serializedData, "application/json");
}

however when it tries to serialize the data I get the following exception:

Token PropertyName in state Property would result in an invalid JSON object. Path 'geometry'.

Solution

  • The reason you get an exception when attempting to serialize a MultiPoint containing an empty List<Point> appears to be due to a bug in the MultiPointConverter, which is used to serialize the list of points. Here is the code for the WriteJson method:

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var points = (List<Point>)value;
        if (points.Any())
        {
            var converter = new PointConverter();
    
            writer.WriteStartArray();
    
            foreach (var point in points)
            {
                converter.WriteJson(writer, point.Coordinates, serializer);
            }
    
            writer.WriteEndArray();
        }
    }
    

    You can see that if the list of points is empty, the converter never writes anything! It should be writing an empty array in this case. The problem is that the property name coordinates has already been written to the output by the time the serializer calls the converter's WriteJson method. If the converter never writes a value, then invalid JSON will be created as soon as the next property name is written. The serializer detects this situation and throws an exception.

    To work around this bug, make sure that your MultiPoint contains at least one Point (ideally it should anyway).

    The corrected converter code would look like this:

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteStartArray();
    
        var points = (List<Point>)value;
        if (points.Any())
        {
            var converter = new PointConverter();
    
            foreach (var point in points)
            {
                converter.WriteJson(writer, point.Coordinates, serializer);
            }
        }
    
        writer.WriteEndArray();
    }