C# 使用Newtonsoft.Json反序列化DbGeometry
我正在使用Angular、Breeze和WebAPI2构建一个水疗中心,遵循John Papa在其最新PluralSight课程中概述的方法 一切都很好,我可以拉信息,更新,插入,删除回服务器。然而,我使用的是空间类型,当我尝试用空间类型更新实体时,我得到以下错误 在中发生“Newtonsoft.Json.JsonSerializationException”类型的异常 Newtonsoft.Json.dll,但未在用户代码中处理 其他信息:从上的“WellKnownValue”获取值时出错 “System.Data.Entity.Spatial.DbGeometry” 内部异常似乎指向WellKnownValue为null这一事实,但事实并非如此,因为我已经检查了发送到服务器的JSON,该JSON随后被发送到Breeze ContextProvider并使用SaveChanges方法保存C# 使用Newtonsoft.Json反序列化DbGeometry,c#,json,breeze,C#,Json,Breeze,我正在使用Angular、Breeze和WebAPI2构建一个水疗中心,遵循John Papa在其最新PluralSight课程中概述的方法 一切都很好,我可以拉信息,更新,插入,删除回服务器。然而,我使用的是空间类型,当我尝试用空间类型更新实体时,我得到以下错误 在中发生“Newtonsoft.Json.JsonSerializationException”类型的异常 Newtonsoft.Json.dll,但未在用户代码中处理 其他信息:从上的“WellKnownValue”获取值时出错 “
{
"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": {}
}
所以我的问题是,是否可以在NewtonSoft库中反序列化DbGeometry类型,如果不可以,有什么建议可以解决这个问题。我不明白为什么不可以。在具有(DbGeometryWellKnownValue)的行上: 这应该是(DbGeometry.WellKnownValue)吗
System.Data.Spatial.DbGeometry
与Newtonsoft.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(CoordinationSystemID)2193硬编码的。 但是,坐标系Id可以出现在问题所示的序列化数据中,也可以出现在WellKnownText“SRID=2193;点(0)”中。此外,此方法将仅读取多边形,但WellKnownText可以是许多内容,如几何体集合、点、线字符串等。要检索此内容,可以更新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);
}
}
我用来序列化和反序列化地理类型变量的是GeoJSON。在这个地址已经有一个未完成的.Net库,尽管仍然缺少一些东西。您可以随时从该项目编写自己的序列化程序/反序列化程序。这种方法也适用于
DbGeography
,您只需将location[“Geometry”][“WellKnownText”]
更改为location[“Geography”][“WellKnownText”]
和DbGeometry converted=DbGeometry.PolygonFromText(值,2193);
到var converted=DbGeography.FromText(值);
我认为对于DbGeographyConverter,您需要使用“Geography”字符串而不是“Geometry”来标记和sridToken。
[JsonConverter(typeof(DbGeometryConverter))]
public DbGeometry Shape { get; set; }
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);
}
}