2014-01-04 6 views
11

Я строю SPA, используя Angular, Breeze и Web API 2, следуя подходу, описанному Джоном Папой в его последнем курсе PluralSight.Deserializing DbGeometry with Newtonsoft.Json

Все работает хорошо, и я могу извлекать информацию, обновлять, вставлять, удалять обратно на сервер. Тем не менее, я использую пространственные тип, и когда я пытаюсь обновить сущность с пространственным типом я получаю следующую ошибку

Исключения типа «Newtonsoft.Json.JsonSerializationException» произошло в Newtonsoft.Json.dll но не обрабатывался в коде пользователя

Дополнительная информация: Ошибка получения значения из 'WellKnownValue' на 'System.Data.Entity.Spatial.DbGeometry'.

Внутреннее исключение, кажется, указывает на то, что 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": {} 
} 

Так что мой вопрос, можно десериализации типы DbGeometry в библиотеке NewtonSoft, а если нет, то какие предложения есть, чтобы обойти это.

+0

Что я использую для сериализации и десериализации переменных типа географии, является GeoJSON. Уже есть незавершенная библиотека для .Net по этому адресу https://github.com/jbattermann/GeoJSON.Net, хотя все еще есть некоторые вещи, вы всегда можете написать свои собственные сериализаторы/десериализаторы из этого проекта. –

ответ

9

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.

Надеюсь, это поможет.

+5

Этот подход хорошо подходит и для 'DbGeography', вам нужно только изменить' location ["Geometry"] ["WellKnownText"] 'to 'location [" География "] [" WellKnownText "]' и 'DbGeometry convert = DbGeometry.PolygonFromText (значение, 2193);' to 'var convert = DbGeography.FromText (value);' –

0

Я не понимаю, почему нет. На линии с (DbGeometryWellKnownValue):

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

это должно быть (DbGeometry.WellKnownValue)?

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

Ответ на этот вопрос отлично работает, но жестко запрограммирован для SRID (CoordinateSystemId) 2193. Идентификатор системы координат, однако, может присутствовать в сериализованных данных, как показано в вопросе, или может присутствовать в WellKnownText «SRID = 2193; POINT (0 0) ". Также этот метод будет читать только многоугольник, но для WellKnownText может быть много чего, например, коллекции геометрии, точки, 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); 
    } 
} 
Смежные вопросы