9

long long zmaga się z tym ...JSON.Net JsonConverter dla DbGeography

Zasadniczo mam modelu pierwszego EF5 obiekt z właściwością DbGeography. Chciałbym zastosować JsonConverter, które pozwolą na objazd jako proste wartości szerokości/długości geograficznej. Używam WebAPI.

Szukasz JSON wyjście i wejście tak:

{ 
    "location": 
    { 
     "geopoint": 
     { 
      "latitude":40.770712, 
      "longitude":-73.962011 
     } 
    } 
} 

Oto moja definicja klasy i JsonConverter:

[MetadataType(typeof(QueryLocationMetadata))] 
partial class Location 
{ 
} 

public class QueryLocationMetadata 
{ 
    [JsonConverter(typeof(DbGeographyConverter))] 
    public virtual DbGeography GeoPoint { get; set; } 
} 


public class DbGeographyConverter : JsonConverter 
{ 
    private const string LATITUDE_KEY = "latitude"; 
    private const string LONGITUDE_KEY = "longitude"; 

    public override bool CanConvert(Type objectType) 
    { 
     return objectType.Equals(typeof(DbGeography)); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.Null) 
      return default(DbGeography); 

     var jObject = JObject.Load(reader); 

     if (!jObject.HasValues || (jObject.Property(LATITUDE_KEY) == null || jObject.Property(LONGITUDE_KEY) == null)) 
      return default(DbGeography); 

     string wkt = string.Format("POINT({1} {0})", jObject[LATITUDE_KEY], jObject[LONGITUDE_KEY]); 
     return DbGeography.FromText(wkt, DbGeography.DefaultCoordinateSystemId); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var dbGeography = value as DbGeography; 

     serializer.Serialize(writer, dbGeography == null || dbGeography.IsEmpty ? null : new { latitude = dbGeography.Latitude.Value, longitude = dbGeography.Longitude.Value }); 
    } 
} 

więc za pomocą tego, że jestem w stanie skutecznie i nawet deserializowania serializacji obiektu poprawnie, ale zanim kiedykolwiek trafiłem w moją akcję ApiController otrzymuję następujący błąd:

System.Data.SqlTypes.SqlNullValueException: Data is Null. This method or property cannot be called on Null values. 
    at System.Data.SqlTypes.SqlDouble.get_Value() 
    at GetValueFromSqlDouble(Object) 
    at System.Web.Http.Metadata.Providers.AssociatedMetadataProvider`1.<>c__DisplayClass3.<GetMetadataForPropertiesImpl>b__0() 
    at System.Web.Http.Metadata.ModelMetadata.get_Model() 
    at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext validationContext, Object container) 
    at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateProperties(ModelMetadata metadata, ValidationContext validationContext) 
    at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext validationContext, Object container) 
    at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateProperties(ModelMetadata metadata, ValidationContext validationContext) 
    at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext validationContext, Object container) 
    at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateProperties(ModelMetadata metadata, ValidationContext validationContext) 
    at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext validationContext, Object container) 
    at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateProperties(ModelMetadata metadata, ValidationContext validationContext) 
    at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext validationContext, Object container) 
    at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateElements(IEnumerable model, ValidationContext validationContext) 
    at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext validationContext, Object container) 
    at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateProperties(ModelMetadata metadata, ValidationContext validationContext) 
    at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext validationContext, Object container) 
    at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateElements(IEnumerable model, ValidationContext validationContext) 
    at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext validationContext, Object container) 
    at System.Web.Http.Validation.DefaultBodyModelValidator.Validate(Object model, Type type, ModelMetadataProvider metadataProvider, HttpActionContext actionContext, String keyPrefix) 
    at System.Web.Http.ModelBinding.FormatterParameterBinding.<>c__DisplayClass1.<ExecuteBindingAsync>b__0(Object model) 
    at System.Threading.Tasks.TaskHelpersExtensions.<>c__DisplayClass36`1.<>c__DisplayClass38.<Then>b__35() 
    at System.Threading.Tasks.TaskHelpersExtensions.<>c__DisplayClass49.<ToAsyncVoidTask>b__48() 
    at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1 func, CancellationToken cancellationToken) 

Po rozglądaniu się i szukaniu w Google różnych rzeczy, jestem absolutnie na straconej pozycji. Rozumiem, że generalnie usiłuje on zweryfikować właściwość, ale SqlDouble?

Odpowiedz

4

Problem nie dotyczy Twojego konwertera. Jest to znany błąd sprawdzania poprawności, który występuje, gdy pobierający obiekt publiczny rzuca się na wykresie obiektu. Pozycja ta praca śledzi problem:

http://aspnetwebstack.codeplex.com/workitem/740

W tym czasie, powinieneś być w stanie uzyskać wokół niego poprzez wyłączenie sprawdzania poprawności:

config.Services.Clear(typeof(ModelValidatorProvider)); 

Przepraszamy za niedogodności.

+0

tymczasowa, czy też nie, przynajmniej pozwala mi zachować trochę włosów na głowie. Dzięki! – Arno

+0

Być może trzeba będzie użyć w pełni kwalifikowanej nazwy: System.Web.Http.Validation.ModelValidatorProvider, jak wspomniano tutaj: https://aspnetwebstack.codeplex.com/workitem/55 – Scott

+0

@Youssef, proszę spojrzeć na link w moim odpowiedź. Jestem ciekawy, czy jest to znany problem. – joelmdev

4

Błąd wspomniane przez Youssef został już rozwiązany, ale nadal prowadził do problemów podczas tworzenia niestandardowych JsonConverter dla DbGeography w tym gdzieś w procesie Walidacja DefaultBodyModelValidator utknął w pętli. Moim rozwiązaniem nie było całkowite wyłączenie sprawdzania poprawności modelu, ale zastąpienie domyślnego sprawdzania poprawności zmiennikiem wyprowadzonym, który wyklucza typ głębokiego sprawdzania poprawności z typu DbGeography.

Tak, aby nie powtarzać, you can see the full solution here.

+0

uratowałeś mi kolejny dzień wściekłości, ten DbGeogrphy jest ... naprawdę bezwartościowym typem, jaki kiedykolwiek widziałem w moim życiu. –

Powiązane problemy