How to seed NetTopologySuite.Geometries.Point data from a Json file in ASP.Net core
NetTopologySuite has a separate nuget, NetTopologySuite.IO.GeoJSON, for serializing NetTopologySuite types from and to JSON using Json.NET. It includes converters for
geometry objects such as Point
. If you add this nuget to your project you will be able to add geometry entities such as Point
to your data model and (de)serialize the model directly.
To do this, first add NetTopologySuite.IO.GeoJSON to your project.
Then add the following extension method:
public static partial class JsonExtensions
{
public static T LoadFromFileWithGeoJson<T>(string path, JsonSerializerSettings settings = null)
{
var serializer = NetTopologySuite.IO.GeoJsonSerializer.CreateDefault(settings);
serializer.CheckAdditionalContent = true;
using (var textReader = new StreamReader(path))
using (var jsonReader = new JsonTextReader(textReader))
{
return serializer.Deserialize<T>(jsonReader);
}
}
}
And add a Location
property to your User
model as in your question:
public class User : IdentityUser<int>
{
public Point Location { get; set; }
// Remainder unchanged.
// ...
}
Now, the JSON format for a Point
looks like:
{"type":"Point","coordinates":[-122.431297,37.773972]}
So edit your JSON file to look like:
[
{
"Location": {
"type": "Point",
"coordinates": [
-122.431297,
37.773972
]
},
// Remainder unchanged
Having done all this, you will be able to deserialize your JSON file quite simply as follows:
var users = JsonExtensions.LoadFromFileWithGeoJson<List<User>>("Data/UserSeedData.json");
Notes:
NetTopologySuite.IO.GeoJSON requires Newtonsoft.Json version 9.0.1 or greater. If you are using a later version you may need to add a
bindingRedirect
to avoid build warnings.See HowTo use [NetTopologySuite.IO.GeoJSON] with ASP.NET Core for additional information on integrating this package in your project.
The
SRID
seems not to be saved as part of the point's JSON. Instead it is set by theIGeometryFactory
used when deserializing thePoint
, which by default isnew GeometryFactory(new PrecisionModel(), 4326);
.If you need control over this you can construct a
JsonSerializer
using a specific factory by usingGeoJsonSerializer.Create(IGeometryFactory factory)
.
Demo fiddle here.
You could subclass NetTopologySuite.Geometries.Point
and add a [JsonConstructor]
to parse your json file. It should be a straightforward substitution for the rest of your code.
public class MyPoint : Point
{
[JsonConstructor]
public MyPoint(double latitude, double longitude, int srid)
:base(new GeoAPI.Geometries.Coordinate(longitude, latitude))
{
SRID = srid;
}
}
Note that latitude = y and longitude = x so the order is reversed.
Swap MyPoint
for Point
in your User
class
public class User: IdentityUser<int> {
// member data here
public MyPoint Location { get; set; }
}
And it should work with your json as is.