如何从ASP.Net核心中的Json文件播种NetTopologySuite.Geometries.Point数据

时间:2019-07-23 22:25:28

标签: c# json asp.net-core-2.2 nettopologysuite

我想从种子文件中为用户对象的“位置”数据注入种子

其中Point是NetTopologySuite.Geometries.Point的c#对象是我的用户对象的一部分

  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数组的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();
}

4 个答案:

答案 0 :(得分: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");

注意:

演示小提琴here

答案 1 :(得分:1)

由于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对象:

"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();
}

总而言之,您可能想重新考虑直接在您的User对象中使用NetTopologySuite的Point对象,而是使用自己的Location对象。然后,您将转置到更接近实际使用Point的代码的NetTopologySuite的Point对象。不过,这实际上取决于您的应用程序。

答案 2 :(得分:1)

您可以继承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,因此顺序相反。

在您的MyPoint类中将Point换成User

public class User: IdentityUser<int> {
  // member data here
  public MyPoint Location { get; set; }
}

它应该可以与您的json一起使用。

答案 3 :(得分:0)

聚会晚了一点,但这是我的看法: 您可以轻松地使Point与您当前的Json Serializer设置兼容。

[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;
}

DataContractDataMember是关键:

new GeoLocation(42.9074, -78.7911).ToJson() => {"longitude":42.9074,"latitude":-78.7911}