2014-09-24 9 views
8

Ich habe eine benutzerdefinierte JsonConverter, die scheinbar nicht korrekt aufgerufen wird. Ich habe den Konverter erstellt, ihn der JsonSerializerSettings.Converters Sammlung hinzugefügt und die Eigenschaft auf der Entität markiert, die ich mit [JsonConverter(typeof(SearchGeoConverter))] serialisiere, aber selbst mit diesen anstelle der Konverter CanConvert Methode sehe ich nie den Typ, den ich versuche zu konvertieren. Ich sehe nur string, int und JObject.JsonConverter CanConvert erhält keinen Typ

Mein Konverter wie folgt aussieht:

public class SearchGeoConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return typeof(DbGeography).IsAssignableFrom(objectType); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var point = (DbGeography) value; 
     var rawJson = string.Format("{{ \"type\": \"Point\", \"coordinates\": [{0}, {1}] }}", point.Latitude, point.Longitude); 
     writer.WriteRaw(rawJson); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Was bin ich?

+0

Klassenmodifikator ist öffentlich? – codebased

+0

Ja, sowohl die Entität als auch der Konverter sind öffentlich. – ilivewithian

Antwort

12

CanConvert wird nicht aufgerufen, wenn Sie etwas mit [JsonConverter] markieren. Wenn Sie das Attribut verwenden, geht Json.Net davon aus, dass Sie den richtigen Konverter bereitgestellt haben, so dass es sich nicht um die Überprüfung der CanConvert handelt. Wenn Sie das Attribut entfernen, wird es aufgerufen, indem Sie die Konverterinstanz an die Einstellungen übergeben. Was Sie sehen, ist Json.Net testet Ihren Konverter für alle anderen Eigenschaftstypen.

EDIT

ich schnell fiddle zusammen zu zeigen, was ich meine (Code auch unten auf Vollständigkeit wiedergegeben wird).

ohne Änderungen das Programm, CanConvert() auf der FooConverter für alle Arten aufgerufen wird außerFoo, aber es wandelt noch Foo richtig.

Wenn Sie das [JsonConverter] Attribut auf dem Wrapper.Foo Eigenschaft kommentieren, können Sie sehen, dass CanConvert() wird nun für Typ Foo aufgrund der FooConverter im JsonSerializerSettings enthalten sind aufgerufen.

Wenn Sie stattdessen die Zeile in Main kommentieren, wo die FooConverter die Einstellungen hinzugefügt wird, dann wird CanConvert nie für jede Art genannt, noch Foo noch korrekt aufgrund des [JsonConverter] auf die Foo Eigenschaft im Wrapper angewandt Attribute umgewandelt wird Klasse.

Also hier ist es, dass es zwei Mechanismen gibt, um anzuzeigen, ob ein Konverter verwendet werden sollte, und Sie beide nicht benötigen. Sie können ein Attribut anwenden und Json.Net mitteilen, dass ein bestimmter Konverter für eine bestimmte Eigenschaft (oder Klasse) verwendet werden soll und der Konverter nicht zuerst abgefragt werden muss. Alternativ können Sie den Konverter zu den Einstellungen hinzufügen. In diesem Fall muss Json.Net jeden Konverter fragen, ob er den jeweiligen Typ verarbeiten kann. Ersteres ist etwas effizienter, während letzteres in Situationen nützlich ist, in denen Sie nicht den Quellcode für die Klasse besitzen, die Sie konvertieren möchten. Hoffe, das macht Sinn.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using Newtonsoft.Json; 
using Newtonsoft.Json.Linq; 
using Newtonsoft.Json.Serialization; 

public class Program 
{ 
    public static void Main() 
    { 
     JsonSerializerSettings settings = new JsonSerializerSettings(); 
     // Comment out the following line and CanConvert() never gets called on 
     // FooConverter for any type yet the FooConverter is still working due 
     // to the JsonConverter attribute applied to Wrapper.Foo 
     settings.Converters.Add(new FooConverter()); 
     settings.Converters.Add(new BarConverter()); 
     settings.Formatting = Formatting.Indented; 

     Wrapper w = new Wrapper 
     { 
      Foo = new Foo 
      { 
       A = "bada", 
       B = "boom", 
      }, 
      Bar = new Bar 
      { 
       C = "bada", 
       D = "bing" 
      } 
     }; 
     string json = JsonConvert.SerializeObject(w, settings); 
     Console.WriteLine(json); 
    } 

    class Wrapper 
    { 
     // Comment out this attribute and CanConvert will be called on FooConverter 
     // for type Foo due to the fact that the FooConverter has been added to the 
     // JsonSerializerSettings 
     [JsonConverter(typeof(FooConverter))] 
     public Foo Foo { get; set; } 
     public Bar Bar { get; set; } 
    } 

    class Foo 
    { 
     public string A { get; set; } 
     public string B { get; set; } 
    } 

    class Bar 
    { 
     public string C { get; set; } 
     public string D { get; set; } 
    } 

    class FooConverter : JsonConverter 
    { 
     public override bool CanConvert(Type objectType) 
     { 
      bool result = typeof(Foo).IsAssignableFrom(objectType); 
      Console.WriteLine("FooConverter CanConvert() called for type " + 
           objectType.Name + " (result = " + result + ")"); 
      return result; 
     } 

     public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
     { 
      var foo = (Foo) value; 
      JObject jo = new JObject(); 
      jo.Add("AplusB", new JValue(foo.A + " " + foo.B)); 
      jo.WriteTo(writer); 
     } 

     public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
     { 
      throw new NotImplementedException(); 
     } 
    } 

    class BarConverter : JsonConverter 
    { 
     public override bool CanConvert(Type objectType) 
     { 
      bool result = typeof(Bar).IsAssignableFrom(objectType); 
      Console.WriteLine("BarConverter CanConvert() called for type " + 
           objectType.Name + " (result = " + result + ")"); 
      return result; 
     } 

     public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
     { 
      var bar = (Bar) value; 
      JObject jo = new JObject(); 
      jo.Add("CplusD", new JValue(bar.C + " " + bar.D)); 
      jo.WriteTo(writer); 
     } 

     public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
     { 
      throw new NotImplementedException(); 
     } 
    } 
}