2015-10-02 20 views
5

JSON.NET viene fornito con attributi di proprietà come [JsonIgnore] e [JsonProperty].Aggiungere un attributo personalizzato a json.net

Desidero creare alcuni personalizzati che vengono eseguiti quando viene eseguita la serializzazione, ad es. [JsonIgnoreSerialize] o [JsonIgnoreDeserialize]

Come farei per estendere il framework per includere questo?

+0

hanno bisogno di essere gli attributi? cosa vuoi fare nel tuo attributo di serializzazione personalizzato? –

+0

Vorrei poter ignorare una proprietà sulla serializzazione ma non sulla deserializzazione. Ho pensato che sarebbe stato semplice aggiungere semplicemente un attributo, ad es. '[JsonIgnoreSerialize]' alla proprietà. –

risposta

2

Poiché l'obiettivo è ignorare una proprietà sulla serializzazione ma non la deserializzazione, è possibile utilizzare uno ContractResolver.

Si noti che la seguente classe fa proprio questo, ed è basata su CamelCasePropertyNamesContractResolver, per assicurarsi che si serializzi su campi Json con casing cammello. Se non lo desideri, puoi invece ereditarlo da DefaultContractResolver.

Inoltre, l'esempio che ho avuto è basato sul nome di una stringa, ma è possibile verificare facilmente se la proprietà è decorata dal proprio attributo personalizzato anziché confrontare il nome della proprietà.

public class CamelCaseIgnoringPropertyJsonResolver<T> : CamelCasePropertyNamesContractResolver 
{   
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) 
    { 
     // list the properties to ignore 
     var propertiesToIgnore = type.GetProperties() 
       .Where(x => x.GetCustomAttributes().OfType<T>().Any()); 

     // Build the properties list 
     var properties = base.CreateProperties(type, memberSerialization); 

     // only serialize properties that are not ignored 
     properties = properties 
      .Where(p => propertiesToIgnore.All(info => info.Name != p.UnderlyingName)) 
      .ToList(); 

     return properties; 
    } 
} 

Quindi, è possibile utilizzarlo come segue:

static private string SerializeMyObject(object myObject) 
    { 
     var settings = new JsonSerializerSettings 
     { 
      ContractResolver = new CamelCaseIgnoringPropertyJsonResolver<JsonIgnoreSerializeAttribute>() 
     }; 

     var json = JsonConvert.SerializeObject(myObject, settings); 
     return json; 
    } 

Infine, l'attributo personalizzato può essere di qualsiasi tipo, ma per abbinare l'esempio:

internal class JsonIgnoreSerializeAttribute : Attribute 
{ 
} 

L'approccio è testato, e funziona anche con oggetti nidificati.

+0

... cura di spiegare il voto negativo? –

+0

Non ho effettuato il downvoting, ma suppongo che il motivo sia che la soluzione in realtà non mostra come implementare gli attributi personalizzati come originariamente richiesto. Invece, si deve passare il nome della proprietà da ignorare al proprio risolutore e gestisce solo quella singola proprietà. Cosa succede se ce ne sono più di uno? –

+0

Abbastanza onesto, Brian. Grazie per il commento costruttivo :) –

5

È possibile scrivere un custom contratto di resolver come questo

public class MyContractResolver<T> : Newtonsoft.Json.Serialization.DefaultContractResolver 
             where T : Attribute 
{ 
    Type _AttributeToIgnore = null; 

    public MyContractResolver() 
    { 
     _AttributeToIgnore = typeof(T); 
    } 

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) 
    { 
     var list = type.GetProperties() 
        .Where(x => !x.GetCustomAttributes().Any(a => a.GetType() == _AttributeToIgnore)) 
        .Select(p => new JsonProperty() 
        { 
         PropertyName = p.Name, 
         PropertyType = p.PropertyType, 
         Readable = true, 
         Writable = true, 
         ValueProvider = base.CreateMemberValueProvider(p) 
        }).ToList(); 

     return list; 
    } 
} 

Si può usare in serializzazione/deserializzazione come

var json = JsonConvert.SerializeObject(
      obj, 
      new JsonSerializerSettings() { 
       ContractResolver = new MyContractResolver<JsonIgnoreSerialize>() 
      }); 

var obj = JsonConvert.DeserializeObject<SomeType>(
      json, 
      new JsonSerializerSettings() { 
       ContractResolver = new MyContractResolver<JsonIgnoreDeserialize>() 
      }); 
+2

Questa soluzione funziona come pubblicizzato, ma ha un problema: non onora gli attributi standard di Json.NET '[JsonIgnore]' e (ancora più importante) '[JsonProperty]'. Vedi https://dotnetfiddle.net/Et265h. Dovresti prima chiamare 'base.CreateProperties()', quindi filtrare quell'elenco in base agli attributi personalizzati. Vedi https://dotnetfiddle.net/gDGfrO. –

Problemi correlati