2014-09-24 15 views
8

Ho un numero personalizzato JsonConverter, che non sembra essere chiamato correttamente. Ho creato il convertitore, l'ho aggiunto alla raccolta JsonSerializerSettings.Converters e contrassegnato la proprietà sull'entità che sto serializzando con [JsonConverter(typeof(SearchGeoConverter))], ma anche con questi in posizione il metodo di conversione CanConvert non vede mai il tipo che sto cercando di convertire. Io vedo sempre, string, int e JObject.JsonConverter CanConvert non riceve il tipo

mio convertitore si presenta così:

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(); 
    } 
} 

Che cosa mi manca?

+0

Il modificatore di classe è pubblico? – codebased

+0

Sì, sia l'entità che il convertitore sono pubblici. – ilivewithian

risposta

12

CanConvert non viene chiamato quando si contrassegna qualcosa con [JsonConverter]. Quando si utilizza l'attributo, Json.Net presuppone che sia stato fornito il convertitore corretto, quindi non si preoccupa del controllo CanConvert. Se rimuovi l'attributo, verrà richiamato in virtù del passaggio dell'istanza del convertitore alle impostazioni. Quello che stai vedendo è Json.Net testare il tuo convertitore per tutti gli altri tipi di proprietà.

EDIT

Ho messo insieme un rapido fiddle per mostrare quello che voglio dire (il codice è anche riprodotto qui di seguito per completezza).

senza modifiche al programma, CanConvert() viene chiamato sul FooConverter per tutti i tipi tranneFoo, eppure converte ancora Foo correttamente.

Se si commento fuori l'attributo [JsonConverter] sulla proprietà Wrapper.Foo, si può vedere che CanConvert() avrà ora chiamato per il tipo Foo in virtù della FooConverter essere inclusi nella JsonSerializerSettings.

Se invece commentare la linea in Main in cui viene aggiunto alle impostazioni della FooConverter, poi CanConvert non viene mai chiamato per qualsiasi tipo, ma Foo è ancora convertito correttamente a causa l'attributo [JsonConverter] applicata alla proprietà Foo nel Wrapper classe.

Quindi il takeaway qui è che ci sono due meccanismi per indicare se un convertitore dovrebbe essere usato, e non è necessario entrambi. È possibile applicare un attributo e questo dirà a Json.Net che un particolare convertitore deve essere utilizzato per una particolare proprietà (o classe) e non è necessario chiedere prima al convertitore. In alternativa, è possibile aggiungere il convertitore alle impostazioni, nel qual caso Json.Net deve chiedere a ciascun convertitore se può gestire ciascun tipo. Il primo è un po 'più efficiente, mentre il secondo è utile in situazioni in cui non si possiede il codice sorgente per la classe che si sta tentando di convertire. Spero che questo abbia un senso.

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(); 
     } 
    } 
} 
Problemi correlati