如何从 ASP.Net 核心中的 Json 文件中播种 NetTopologySuite.Geometries.Point 数据
Posted
技术标签:
【中文标题】如何从 ASP.Net 核心中的 Json 文件中播种 NetTopologySuite.Geometries.Point 数据【英文标题】:How to seed NetTopologySuite.Geometries.Point data from a Json file in ASP.Net core 【发布时间】:2019-12-02 00:29:05 【问题描述】:我想从我的种子文件中为我的用户对象播种“位置”数据
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 RoleName = "Member",
new RoleName = "Admin",
new RoleName = "Moderator",
new RoleName = "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 数组的 json 文件“UserSeedData.json”,我希望能够在其中粘贴某种代表 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();
【问题讨论】:
能否确认您使用的是nuget.org/packages/NetTopologySuite.IO.GeoJSON,并告知具体版本? 我使用的是最新版本的 NetTopologySuite 【参考方案1】:由于 NetTopogiySuite 的 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 对象。然后,您将转置到更接近实际使用 Point 的代码的 NetTopologySuite 的 Point 对象。不过,这实际上取决于您的应用程序。
【讨论】:
如果您查看我的帖子,您会发现您的解决方案与我目前正在做的非常相似,而不是我想要的。 @user1186050 很公平。但是您的帖子询问了如何从 JSON 文件中获取数据,我的示例是这样做的,而您的则没有。【参考方案2】:NetTopologySuite 有一个单独的 nuget,NetTopologySuite.IO.GeoJSON,用于使用 Json.NET 将 NetTopologySuite 类型从 JSON 序列化到 JSON 序列化。它包括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
似乎没有保存为点的 JSON 的一部分。相反,它由反序列化Point
时使用的IGeometryFactory
设置,默认情况下为new GeometryFactory(new PrecisionModel(), 4326);
。
如果您需要对此进行控制,您可以使用GeoJsonSerializer.Create(IGeometryFactory factory)
使用特定工厂构造JsonSerializer
。
演示小提琴here.
【讨论】:
这可能行得通,但它似乎比我目前正在做的解决方案更复杂,所以我不会奖励任何积分。 重点是它更正确,因为您将使用为您要反序列化的类设计的转换器。此外,一旦编写了这些扩展方法,它们就可以与任何包含NetTopologySuite.Geometries
内容的数据模型一起使用。
但是,如果您查看我当前的解决方案,我不必做任何这些...非常正确!= 简单,除了播种我的数据之外,我不需要它任何地方在初始构建时到我的数据库。如果您查看我如何需要它以及我在哪里使用它,这是一次性用例。无效种子用户()
仅供参考,演示行 404 上方的两个链接。【参考方案3】:
您可以继承 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;
注意 latitude = y 和 longitude = x 所以顺序是相反的。
在User
类中将MyPoint
替换为Point
public class User: IdentityUser<int>
// member data here
public MyPoint Location get; set;
它应该可以与您的 json 一起使用。
【讨论】:
【参考方案4】:聚会有点晚了,但这是我对此的看法:
您可以轻松地使 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
【讨论】:
以上是关于如何从 ASP.Net 核心中的 Json 文件中播种 NetTopologySuite.Geometries.Point 数据的主要内容,如果未能解决你的问题,请参考以下文章
无法解析 JSON 文件,Progam.cs asp.net 核心中的错误
谷歌驱动器重定向 URI 不匹配以及如何从 ASP.net 核心 2.0 中的谷歌驱动器获取文件列表