使用Newtonsoft.Json反序列化DbGeometry

我正在按照John Papa在其最新的PluralSight课程中概述的方法,使用Angular,Breeze和Web API 2构建SPA。

一切运作良好,我可以提取信息,更新,插入,删除回服务器。 但是我正在使用空间类型,当我尝试更新具有空间类型的实体时,我得到以下错误

Newtonsoft.Json.dll中出现“Newtonsoft.Json.JsonSerializationException”类型的exception,但未在用户代码中处理

附加信息:从’System.Data.Entity.Spatial.DbGeometry’上的’WellKnownValue’获取值时出错。

内部exception似乎指向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://sofzh.miximages.com/c%23/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": {} } 

所以我的问题是,可以在NewtonSoft库中反序列化DbGeometry类型,如果没有,有什么建议可以解决这个问题。

System.Data.Spatial.DbGeometryNewtonsoft.Json不能很好地协同工作

您需要创建一个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); } } 

然后在模型中的属性上添加属性

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

现在,当您点击BreezeController时,反序列化将由我们的新DbGeometryConverter处理。

希望能帮助到你。

上面的答案很有效,但是对于SRID(CoordinateSystemId)2193是硬编码的。然而,坐标系统ID可以出现在问题中所示的序列化数据中,或者它可以出现在WellKnownText“SRID = 2193; POINT(0)中0)”。 此方法也只会读取多边形,但WellKnownText可以是很多东西,如Geometry Collections,Point,Linestring等。要进行检索,可以更新ReadJson方法以使用更通用的FromText方法,如下所示。 以上是使用更通用的坐标系更新的类,也适用于任何几何类型。 我还添加了地理版本以供参考。

 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["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. //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); } } 

我不明白为什么不。 在(DbGeometryWellKnownValue)的行上:

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

应该是(DbGeometry.WellKnownValue)?

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