简体   繁体   English

使用 Newtonsoft.Json 反序列化 DbGeometry

[英]Deserializing DbGeometry with Newtonsoft.Json

I'm building a SPA using Angular,Breeze and Web API 2 following the approach as outlined by John Papa in his latest PluralSight course.我正在按照 John Papa 在他最新的 PluralSight 课程中概述的方法使用 Angular、Breeze 和 Web API 2 构建 SPA。

Everything works well and I can pull information, update, insert, delete back to the server.一切正常,我可以将信息、更新、插入、删除回服务器。 However I'm using Spatial Types, and when I try to update an entity with a spatial type I get the following error但是,我使用的是空间类型,当我尝试使用空间类型更新实体时,出现以下错误

An exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll but was not handled in user code Newtonsoft.Json.dll 中发生了“Newtonsoft.Json.JsonSerializationException”类型的异常,但未在用户代码中处理

Additional information: Error getting value from 'WellKnownValue' on 'System.Data.Entity.Spatial.DbGeometry'.附加信息:从“System.Data.Entity.Spatial.DbGeometry”上的“WellKnownValue”获取值时出错。

The inner exception seems to point to the fact that the WellKnownValue is null, its not though, as I have checked the JSON being sent to the server which is then sent to the Breeze ContextProvider and saved using the SaveChanges method.内部异常似乎指向 WellKnownValue 为空的事实,但它不是,因为我已经检查了发送到服务器的 JSON,然后将其发送到 Breeze ContextProvider 并使用 SaveChanges 方法保存。

{
"entities": [
 {
  "TableKey": 2,
  "CaseName": "Mikhail Lermontov",
  "StartDate": "2013-06-11T00:00:00Z",
  "EndDate": null,
  "IsCurrent": true,
  "SRID": 109,
  "Shape": {
    "$id": "2",
    "$type": "System.Data.Entity.Spatial.DbGeometry, EntityFramework",
    "Geometry": {
      "$id": "3",
      "$type": "System.Data.Entity.Spatial.DbGeometryWellKnownValue, EntityFramework",
      "CoordinateSystemId": 2193,
      "WellKnownText": "POLYGON ((1695943 5462665, 1713098 5462665, 1713098 5449659, 1695943 5449659, 1695943 5462665))"
    }
  },
  "SpillLocation": "Marlborough Sounds",
  "Image": "http://www.nzmaritime.co.nz/images/lm5.jpg\r\n",
  "DefaultBaseMapKey": 2,
  "__unmapped": {
    "isPartial": false
  },
  "entityAspect": {
    "entityTypeName": "DatSpillCase:#Osiris.Model",
    "defaultResourceName": "DatSpillCases",
    "entityState": "Modified",
    "originalValuesMap": {
      "CaseName": "Mikhail Lermontov"
    },
    "autoGeneratedKey": {
      "propertyName": "TableKey",
      "autoGeneratedKeyType": "Identity"
    }
  }
}
 ],
  "saveOptions": {}
}

So my question is, is possible to deserialize DbGeometry types within the NewtonSoft library, and if not, what suggestions are there to get around that.所以我的问题是,是否可以在 NewtonSoft 库中反序列化 DbGeometry 类型,如果没有,有什么建议可以解决这个问题。

System.Data.Spatial.DbGeometry does not play nicely with Newtonsoft.Json System.Data.Spatial.DbGeometry不能很好地与Newtonsoft.Json配合使用

You need to create a JsonConverter to convert the DbGeometry您需要创建一个JsonConverter来转换DbGeometry

public class DbGeometryConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return objectType.IsAssignableFrom(typeof(string));
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JObject location = JObject.Load(reader);
            JToken token = location["Geometry"]["WellKnownText"];
            string value = token.ToString();

            DbGeometry converted = DbGeometry.PolygonFromText(value, 2193);
            return converted;
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            // Base serialization is fine
            serializer.Serialize(writer, value);
        }
    }

Then on your property in your model add the attribute然后在模型中的属性上添加属性

[JsonConverter(typeof(DbGeometryConverter))]
public DbGeometry Shape { get; set; }

Now when you hit your BreezeController the deserialization will be handled by our new DbGeometryConverter.现在,当您点击 BreezeController 时,反序列化将由我们新的 DbGeometryConverter 处理。

Hope it helps.希望它有帮助。

The answer above works great, but is hardcoded for SRID (CoordinateSystemId) 2193. The Coordinate System Id can however be present in the serialised data as shown in the question, or it can be present in the WellKnownText "SRID=2193;POINT (0 0)".上面的答案很好用,但对 SRID (CoordinateSystemId) 2193 进行了硬编码。 然而,坐标系 Id 可以出现在问题中所示的序列化数据中,或者它可以出现在 WellKnownText "SRID=2193;POINT (0 0)”。 Also this method will only read a polygon, but the WellKnownText can be a lot of things, like Geometry Collections, Point, Linestring, etc. To retreive this the ReadJson method can be updated to use the more generic FromText method as shown below.此外,此方法只会读取多边形,但 WellKnownText 可以是很多东西,例如几何集合、点、线串等。要检索它,可以更新 ReadJson 方法以使用更通用的 FromText 方法,如下所示。 Here is the class above updated with a more generic Coordinate System, and also for any Geometry Type.这是上面用更通用的坐标系更新的类,也适用于任何几何类型。 I have also added the Geography version for reference.我还添加了地理版本以供参考。

public class DbGeometryConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType.IsAssignableFrom(typeof(string));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject location = JObject.Load(reader);
        JToken token = location["Geometry"]["WellKnownText"];
        string value = token.ToString();
        JToken sridToken = location["Geometry"]["CoordinateSystemId"];
        int srid;
        if (sridToken == null || int.TryParse(sridToken.ToString(), out srid) == false || value.Contains("SRID"))
        {
            //Set default coordinate system here.
            srid = 0;
        }

        DbGeometry converted;
        if (srid > 0)
            converted = DbGeometry.FromText(value, srid);
        else
            converted = DbGeometry.FromText(value);
        return converted;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // Base serialization is fine
        serializer.Serialize(writer, value);
    }
}

public class DbGeographyConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType.IsAssignableFrom(typeof(string));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject location = JObject.Load(reader);
        JToken token = location["Geography"]["WellKnownText"];
        string value = token.ToString();
        JToken sridToken = location["Geography"]["CoordinateSystemId"];
        int srid;
        if (sridToken == null || int.TryParse(sridToken.ToString(), out srid) == false || value.Contains("SRID"))
        {
            //Set default coordinate system here.
            //NOTE: Geography should always have an SRID, and it has to match the data in the database else all comparisons will return NULL!
            srid = 0;
        }
        DbGeography converted;
        if (srid > 0)
            converted = DbGeography.FromText(value, srid);
        else
            converted = DbGeography.FromText(value);
        return converted;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // Base serialization is fine
        serializer.Serialize(writer, value);
    }
}

I don't see why not.我不明白为什么不。 On the line with (DbGeometryWellKnownValue):在 (DbGeometryWellKnownValue) 线上:

"$type": "System.Data.Entity.Spatial.DbGeometryWellKnownValue, EntityFramework",

should this be (DbGeometry.WellKnownValue)?这应该是 (DbGeometry.WellKnownValue) 吗?

  "$type": "System.Data.Entity.Spatial.DbGeometry.WellKnownValue, EntityFramework",

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM