如何从 ASP.Net 核心中的 Json 文件播种 NetTopologySuite.Geometries.Point 数据
How to seed NetTopologySuite.Geometries.Point data from a Json file in ASP.Net core
我想从我的种子文件中为我的用户对象播种 "Location" 数据
C# 对象,其中 Point 是一个 NetTopologySuite.Geometries.Point
是我的用户对象的一部分
public class User: IdentityUser<int> {
// member data here
public Point Location { get; set; } // has lat/lng data points
}
我通过做这样的事情在启动时将数据播种到我的数据库
public void SeedUsers()
{
if (!_userManager.Users.Any())
{
var userData = System.IO.File.ReadAllText("Data/UserSeedData.json");
var users = JsonConvert.DeserializeObject<List<User>>(userData);
var roles = new List<Role>
{
new Role{Name = "Member"},
new Role{Name = "Admin"},
new Role{Name = "Moderator"},
new Role{Name = "VIP"},
};
foreach (var role in roles)
{
_roleManager.CreateAsync(role).Wait();
}
foreach (var user in users)
{
user.Photos.SingleOrDefault().IsApproved = true;
_userManager.CreateAsync(user, "password").Wait();
_userManager.AddToRoleAsync(user, "Member").Wait();
}
}
}
有一个 json 文件 "UserSeedData.json" 的 json 这样的数组,我希望能够在其中粘贴某种 'Location' 数据,代表lng/lat 个数据点。
{
"Email": "myemailaddress@gmail.com",
"Username": "Lola",
"Gender": "female",
"DateOfBirth": "1994-02-21",
"Password": "password",
"Created": "2017-08-02",
"LastActive": "2017-08-02",
"Introduction": "blah blah blah",
"LookingFor": "blah blah blah",
"City": "San Francisco",
"Country": "United States",
"Longitude": -122.431297,
"Latitude": 37.773972,
"Location": // something here!!!
"Photos": [{
"url": "https://randomuser.me/api/portraits/women/3.jpg",
"isMain": true,
"description": "Non deserunt labore sunt ex laboris et adipisicing ullamco officia minim."
}]
}
现在我知道在我的种子方法中我可以做这样的事情,但我正在寻找一种方法将它包含在我的 .json 文件中,这样我就可以使用不同的数据点
foreach (var user in users)
{
user.Photos.SingleOrDefault().IsApproved = true;
user.Location = new Point(-122.4194155, 37.7749295) { SRID = 4326 };
_userManager.CreateAsync(user, "password").Wait();
_userManager.AddToRoleAsync(user, "Member").Wait();
}
因为 NetTopologiySuite 的 Point 对象不包含无参数构造函数,所以在反序列化过程中无法轻松映射 JSON。
但是,您可以轻松地创建自己的 Location 对象,然后将值映射到循环中的 NetTopologySuite 的 Point 对象。
首先,定义一个新的 Location 对象...
public class Location
{
public double Longitude { get; set; }
public double Latitude { get; set; }
public int SRID { get; set; }
}
接下来,使用以下行更新您的 JSON 的位置行以定义 Location 对象:
"Location": {"Longitude":-122.4194155, "Latitude":37.7749295, "SRID":4326},
完整 JSON:
[{
"Email": "myemailaddress@gmail.com",
"Username": "Lola",
"Gender": "female",
"DateOfBirth": "1994-02-21",
"Password": "password",
"Created": "2017-08-02",
"LastActive": "2017-08-02",
"Introduction": "blah blah blah",
"LookingFor": "blah blah blah",
"City": "San Francisco",
"Country": "United States",
"Longitude": -122.431297,
"Latitude": 37.773972,
"Location": {"Longitude":-122.4194155, "Latitude":37.7749295, "SRID":4326},
"Photos": [{
"url": "https://randomuser.me/api/portraits/women/3.jpg",
"isMain": true,
"description": "Non deserunt labore sunt ex laboris et adipisicing ullamco officia minim."
}]
}]
接下来,更新您的 User 对象以使用新的 Location 对象并在 NetTopologySuite 的 Point 对象上设置 JsonIgnore 属性:
public class User : IdentityUser<int>
{
// member data here
public Location Location { get; set; }
[JsonIgnore]
public Point LocationPoint { get; set; } // has lat/lng data points
}
最后,更新您的 foreach 循环以映射数据...
foreach (var user in users)
{
user.Photos.SingleOrDefault().IsApproved = true;
user.LocationPoint = new Point(user.Location.Longitude, user.Location.Latitude) {SRID = user.Location.SRID};
_userManager.CreateAsync(user, "password").Wait();
_userManager.AddToRoleAsync(user, "Member").Wait();
}
总而言之,您可能需要重新考虑直接在您的用户对象中使用 NetTopologySuite 的 Point 对象,而是使用您自己的 Location 对象。然后,您可以将 NetTopologySuite 的 Point 对象转置为更接近实际使用 Point 的代码。不过,这实际上取决于您的应用程序。
NetTopologySuite has a separate nuget, NetTopologySuite.IO.GeoJSON, for serializing NetTopologySuite types from and to JSON using Json.NET. It includes converters 为
几何对象,例如 Point
。如果将此 nuget 添加到项目中,您将能够将 Point
等几何实体添加到数据模型中,并直接(反)序列化模型。
为此,请先将 NetTopologySuite.IO.GeoJSON 添加到您的项目中。
然后添加如下扩展方法:
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);
}
}
}
然后将 Location
属性 添加到您的 User
模型中,如您的问题:
public class User : IdentityUser<int>
{
public Point Location { get; set; }
// Remainder unchanged.
// ...
}
现在,Point
的 JSON 格式如下所示:
{"type":"Point","coordinates":[-122.431297,37.773972]}
因此,将您的 JSON 文件编辑为:
[
{
"Location": {
"type": "Point",
"coordinates": [
-122.431297,
37.773972
]
},
// Remainder unchanged
完成所有这些后,您将能够非常简单地反序列化您的 JSON 文件,如下所示:
var users = JsonExtensions.LoadFromFileWithGeoJson<List<User>>("Data/UserSeedData.json");
备注:
NetTopologySuite.IO.GeoJSON 需要 Newtonsoft.Json 版本 9.0.1 或更高版本。如果您使用的是更高版本,您可能需要添加 bindingRedirect
以避免生成警告。
查看HowTo use [NetTopologySuite.IO.GeoJSON] with ASP.NET Core了解有关将此包集成到项目中的更多信息。
SRID
seems not to be saved as part of the point's JSON. Instead it is set by the IGeometryFactory
used when deserializing the Point
, which by default is new GeometryFactory(new PrecisionModel(), 4326);
。
如果您需要对此进行控制,您可以通过使用 GeoJsonSerializer.Create(IGeometryFactory factory)
.
使用特定工厂构造一个 JsonSerializer
演示 fiddle here.
您可以子class NetTopologySuite.Geometries.Point
并添加一个 [JsonConstructor]
来解析您的 json 文件。它应该是对其余代码的直接替代。
public class MyPoint : Point
{
[JsonConstructor]
public MyPoint(double latitude, double longitude, int srid)
:base(new GeoAPI.Geometries.Coordinate(longitude, latitude))
{
SRID = srid;
}
}
请注意,纬度 = y,经度 = x,所以顺序是相反的。
在您的 User
class
中将 MyPoint
换成 Point
public class User: IdentityUser<int> {
// member data here
public MyPoint Location { get; set; }
}
它应该可以与您的 json 一起使用。
聚会有点晚了,但这是我的看法:
您可以轻松地使 Point
与您当前的 Json 序列化程序设置兼容。
[DataContract]
public class GeoLocation : NetTopologySuite.Geometries.Point
{
const int GoogleMapSRID = 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;
}
DataContract
和 DataMember
是这里的关键:
new GeoLocation(42.9074, -78.7911).ToJson() => {"longitude":42.9074,"latitude":-78.7911}
我想从我的种子文件中为我的用户对象播种 "Location" 数据
C# 对象,其中 Point 是一个 NetTopologySuite.Geometries.Point
是我的用户对象的一部分
public class User: IdentityUser<int> {
// member data here
public Point Location { get; set; } // has lat/lng data points
}
我通过做这样的事情在启动时将数据播种到我的数据库
public void SeedUsers()
{
if (!_userManager.Users.Any())
{
var userData = System.IO.File.ReadAllText("Data/UserSeedData.json");
var users = JsonConvert.DeserializeObject<List<User>>(userData);
var roles = new List<Role>
{
new Role{Name = "Member"},
new Role{Name = "Admin"},
new Role{Name = "Moderator"},
new Role{Name = "VIP"},
};
foreach (var role in roles)
{
_roleManager.CreateAsync(role).Wait();
}
foreach (var user in users)
{
user.Photos.SingleOrDefault().IsApproved = true;
_userManager.CreateAsync(user, "password").Wait();
_userManager.AddToRoleAsync(user, "Member").Wait();
}
}
}
有一个 json 文件 "UserSeedData.json" 的 json 这样的数组,我希望能够在其中粘贴某种 'Location' 数据,代表lng/lat 个数据点。
{
"Email": "myemailaddress@gmail.com",
"Username": "Lola",
"Gender": "female",
"DateOfBirth": "1994-02-21",
"Password": "password",
"Created": "2017-08-02",
"LastActive": "2017-08-02",
"Introduction": "blah blah blah",
"LookingFor": "blah blah blah",
"City": "San Francisco",
"Country": "United States",
"Longitude": -122.431297,
"Latitude": 37.773972,
"Location": // something here!!!
"Photos": [{
"url": "https://randomuser.me/api/portraits/women/3.jpg",
"isMain": true,
"description": "Non deserunt labore sunt ex laboris et adipisicing ullamco officia minim."
}]
}
现在我知道在我的种子方法中我可以做这样的事情,但我正在寻找一种方法将它包含在我的 .json 文件中,这样我就可以使用不同的数据点
foreach (var user in users)
{
user.Photos.SingleOrDefault().IsApproved = true;
user.Location = new Point(-122.4194155, 37.7749295) { SRID = 4326 };
_userManager.CreateAsync(user, "password").Wait();
_userManager.AddToRoleAsync(user, "Member").Wait();
}
因为 NetTopologiySuite 的 Point 对象不包含无参数构造函数,所以在反序列化过程中无法轻松映射 JSON。
但是,您可以轻松地创建自己的 Location 对象,然后将值映射到循环中的 NetTopologySuite 的 Point 对象。
首先,定义一个新的 Location 对象...
public class Location
{
public double Longitude { get; set; }
public double Latitude { get; set; }
public int SRID { get; set; }
}
接下来,使用以下行更新您的 JSON 的位置行以定义 Location 对象:
"Location": {"Longitude":-122.4194155, "Latitude":37.7749295, "SRID":4326},
完整 JSON:
[{
"Email": "myemailaddress@gmail.com",
"Username": "Lola",
"Gender": "female",
"DateOfBirth": "1994-02-21",
"Password": "password",
"Created": "2017-08-02",
"LastActive": "2017-08-02",
"Introduction": "blah blah blah",
"LookingFor": "blah blah blah",
"City": "San Francisco",
"Country": "United States",
"Longitude": -122.431297,
"Latitude": 37.773972,
"Location": {"Longitude":-122.4194155, "Latitude":37.7749295, "SRID":4326},
"Photos": [{
"url": "https://randomuser.me/api/portraits/women/3.jpg",
"isMain": true,
"description": "Non deserunt labore sunt ex laboris et adipisicing ullamco officia minim."
}]
}]
接下来,更新您的 User 对象以使用新的 Location 对象并在 NetTopologySuite 的 Point 对象上设置 JsonIgnore 属性:
public class User : IdentityUser<int>
{
// member data here
public Location Location { get; set; }
[JsonIgnore]
public Point LocationPoint { get; set; } // has lat/lng data points
}
最后,更新您的 foreach 循环以映射数据...
foreach (var user in users)
{
user.Photos.SingleOrDefault().IsApproved = true;
user.LocationPoint = new Point(user.Location.Longitude, user.Location.Latitude) {SRID = user.Location.SRID};
_userManager.CreateAsync(user, "password").Wait();
_userManager.AddToRoleAsync(user, "Member").Wait();
}
总而言之,您可能需要重新考虑直接在您的用户对象中使用 NetTopologySuite 的 Point 对象,而是使用您自己的 Location 对象。然后,您可以将 NetTopologySuite 的 Point 对象转置为更接近实际使用 Point 的代码。不过,这实际上取决于您的应用程序。
NetTopologySuite has a separate nuget, NetTopologySuite.IO.GeoJSON, for serializing NetTopologySuite types from and to JSON using Json.NET. It includes converters 为
几何对象,例如 Point
。如果将此 nuget 添加到项目中,您将能够将 Point
等几何实体添加到数据模型中,并直接(反)序列化模型。
为此,请先将 NetTopologySuite.IO.GeoJSON 添加到您的项目中。
然后添加如下扩展方法:
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);
}
}
}
然后将 Location
属性 添加到您的 User
模型中,如您的问题:
public class User : IdentityUser<int>
{
public Point Location { get; set; }
// Remainder unchanged.
// ...
}
现在,Point
的 JSON 格式如下所示:
{"type":"Point","coordinates":[-122.431297,37.773972]}
因此,将您的 JSON 文件编辑为:
[
{
"Location": {
"type": "Point",
"coordinates": [
-122.431297,
37.773972
]
},
// Remainder unchanged
完成所有这些后,您将能够非常简单地反序列化您的 JSON 文件,如下所示:
var users = JsonExtensions.LoadFromFileWithGeoJson<List<User>>("Data/UserSeedData.json");
备注:
NetTopologySuite.IO.GeoJSON 需要 Newtonsoft.Json 版本 9.0.1 或更高版本。如果您使用的是更高版本,您可能需要添加
bindingRedirect
以避免生成警告。查看HowTo use [NetTopologySuite.IO.GeoJSON] with ASP.NET Core了解有关将此包集成到项目中的更多信息。
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);
。如果您需要对此进行控制,您可以通过使用
GeoJsonSerializer.Create(IGeometryFactory factory)
. 使用特定工厂构造一个
JsonSerializer
演示 fiddle here.
您可以子class NetTopologySuite.Geometries.Point
并添加一个 [JsonConstructor]
来解析您的 json 文件。它应该是对其余代码的直接替代。
public class MyPoint : Point
{
[JsonConstructor]
public MyPoint(double latitude, double longitude, int srid)
:base(new GeoAPI.Geometries.Coordinate(longitude, latitude))
{
SRID = srid;
}
}
请注意,纬度 = y,经度 = x,所以顺序是相反的。
在您的 User
class
MyPoint
换成 Point
public class User: IdentityUser<int> {
// member data here
public MyPoint Location { get; set; }
}
它应该可以与您的 json 一起使用。
聚会有点晚了,但这是我的看法:
您可以轻松地使 Point
与您当前的 Json 序列化程序设置兼容。
[DataContract]
public class GeoLocation : NetTopologySuite.Geometries.Point
{
const int GoogleMapSRID = 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;
}
DataContract
和 DataMember
是这里的关键:
new GeoLocation(42.9074, -78.7911).ToJson() => {"longitude":42.9074,"latitude":-78.7911}