Having trouble serializing NetTopologySuite FeaturesCollection to GeoJSON
Asked Answered
G

4

13

Trying to return some pretty simple GeoJSON data. I found NetTopologySuite, and set up a simple FeaturesCollection and tried to serialize it out to a GeoJson string only to get the following error:

"Self referencing loop detected for property 'CoordinateValue' with type 'GeoAPI.Geometries.Coordinate'. Path 'Features[0].Geometry.Coordinates[0]'."

Looking through the class headers, Point uses Coordinate, which does have a Coordinate property so I can see why there would be a circular reference. The thing is, most (if not all) the Geometries seem to use Point, so that would make it impossible to ever serialize anything... unless I'm missing something.

So is this a bug or am I missing something?

Tested with just a Point and got the same error, so here's the code for that:

using NTS = NetTopologySuite;

var ret = new NTS.Geometries.Point(42.9074, -78.7911);

var jsonSerializer = NTS.IO.GeoJsonSerializer.Create();

var sw = new System.IO.StringWriter();
jsonSerializer.Serialize(sw, ret);

var json = sw.ToString();
Gothicism answered 5/11, 2014 at 17:36 Comment(3)
What is this Create() method? I don't see it here.Circumstantial
If you are using a modified constructor for GeoJsonSerializer, you need to make sure a CoordinateConverter is passed to it, as is shown here.Circumstantial
Create() is part of the parent class (apparently.) Switching to the default constructor works perfectly. Feel free to make that an actual answer and I'll mark it. :)Gothicism
C
5

Update

GeoJsonSerializer has been moved to NetTopologySuite.IO.GeoJSON and now has its own static Create() method:

/// <summary>
/// Factory method to create a (Geo)JsonSerializer
/// </summary>
/// <remarks>Calls <see cref="GeoJsonSerializer.CreateDefault()"/> internally</remarks>
/// <returns>A <see cref="JsonSerializer"/></returns>
public new static JsonSerializer Create()
{
    return CreateDefault();
}

Use of the direct constructor has been deprecated:

[Obsolete("Use GeoJsonSerializer.Create...() functions")]
public GeoJsonSerializer() : this(Wgs84Factory) { }

The code in the question should now work as expected.


Original Answer

Use the default constructor for the GeoJsonSerializer class:

var jsonSerializer = new NetTopologySuite.IO.GeoJsonSerializer();

That attaches a CoordinateConverter which prevents the problem.

GeoJsonSerializer does not actually have a static Create() method, so you are falling back on the base class's JsonSerializer.Create(). In fact the following would have resulted in a compiler error:

GeoJsonSerializer jsonSerializer = NTS.IO.GeoJsonSerializer.Create();
Circumstantial answered 5/11, 2014 at 22:2 Comment(1)
The answer is slightly outdated and doesn't mention GeoJSON4STJMalan
M
0

Instead of returning Json after you have serialized already, you can use :

        return Content(sw.ToString, "application/Json");
Meteorite answered 16/12, 2015 at 17:46 Comment(0)
I
0

A bit late to the party but here is my take on this: you can easily easily make the Point compatible with your current Json Serializer settings.

[DataContract]
public class GeoLocation : NetTopologySuite.Geometries.Point
{
    const int GoogleMapsSRID = 4326 ;

    public GeoLocation(double latitude, double longitude)
        : base(x: longitude, y: latitude) =>
          base.SRID = GoogleMapsSRID;

    [DataMember]
    public double Longitude => base.X;

    [DataMember]
    public double Latitude => base.Y;
}

The DataContract and DataMember are key here:

new GeoLocation(42.9074, -78.7911).ToJson() => {"longitude":42.9074,"latitude":-78.7911}
Isabelisabelita answered 9/3, 2020 at 4:24 Comment(1)
When trying this I get System.InvalidCastException: Unable to cast object of type 'NetTopologySuite.Geometries.Point' to type 'TrackingAPI.Data.MyPoint'.Ers
P
0

I found this to be the simplest approach using the NetTopologySuite.IO.GeoJSON package (dotnet add package NetTopologySuite.IO.GeoJSON)

using NetTopologySuite.IO;
using NTS = NetTopologySuite;

GeoJsonWriter _geoJsonWriter = new();

var ret = new NTS.Geometries.Point(42.9074, -78.7911);
string json = _geoJsonWriter.Write(ret);
Pitarys answered 18/1 at 11:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.