9

Lange lange Kämpfe mit diesem ...JSON.Net JsonConverter für DbGeography

Im Prinzip habe ich ein Modell-first EF5 Objekt mit einer DbGeography Eigenschaft. Ich möchte eine JsonConverter anwenden, die es als einfache Breiten-/Längengrad-Werte runden lässt. Ich verwende WebAPI.

der Suche nach JSON Ausgabe und Eingabe wie folgt:

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

Hier ist meine Klassendefinition und 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 }); 
    } 
} 

diese So verwenden ich bin in der Lage, erfolgreich serialisiert werden und sogar ein Objekt deserialisieren richtig, aber bevor ich jemals meine ApiController Aktion treffe bekomme ich den folgenden Fehler:

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) 

Nachdem ich herumgespielt und alle möglichen Dinge gegoogelt habe, bin ich absolut ratlos. Ich bekomme, dass es im Allgemeinen versucht, die Eigenschaft zu validieren, aber ein SqlDouble?

Antwort

4

Das Problem ist nicht mit Ihrem Konverter. Dies ist ein bekannter Überprüfungsfehler, der auftritt, wenn der Getter einer öffentlichen Eigenschaft das Objektdiagramm auslöst. Dieses Workitem verfolgt die Frage:

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

In der Zwischenzeit sollten Sie in der Lage sein, um es zu erhalten, indem die Validierung zu deaktivieren:

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

Es tut uns leid.

+0

Temporary oder nicht, zumindest, dass ich einige der Haare auf dem Kopf halten läßt. Vielen Dank! – Arno

+0

Sie müssen möglicherweise den voll qualifizierten Namen verwenden: System.Web.Http.Validation.ModelValidatorProvider wie hier erwähnt: https://aspnetwebstack.codeplex.com/workitem/55 – Scott

+0

@Youssef, bitte werfen Sie einen Blick auf den Link in meinem Antworten. Ich bin neugierig zu wissen, ob dies ein bekanntes Problem ist. – joelmdev

4

Die von Youssef erwähnten Bug wurde behoben, da, aber ich lief immer noch in Probleme, wenn eine benutzerdefinierte JsonConverter für DbGeography dass irgendwo im Validierungsprozess Schaffung der DefaultBodyModelValidator in einer Schleife stecken geblieben. Meine Lösung bestand nicht darin, die Modellvalidierung zu deaktivieren, sondern den Standardvalidierer durch einen abgeleiteten zu ersetzen, der den Typ DbGeography von der Tiefenvalidierung ausschließt.

Um mich nicht zu wiederholen, you can see the full solution here.

+0

Sie rettete mich einen anderen Tag der Wut, dieser DbGeogrphy ist .... wirklich der wertlose Typ, den ich jemals in meinem Leben gesehen habe. –

Verwandte Themen