2015-09-29 11 views
8

In un'applicazione API Web ASP.NET, alcuni dei modelli con cui sto lavorando contengono una porzione di JSON ad-hoc che è utile solo sul lato client . Sul server entra e esce da un database relazionale come una stringa. Le prestazioni sono fondamentali e sembra inutile elaborare il lato del server delle stringhe JSON.Json.NET - impedire la serializzazione di una proprietà già serializzata

Quindi, in C#, immaginare un oggetto come questo:

new Person 
{ 
    FirstName = "John", 
    LastName = "Smith", 
    Json = "{ \"Age\": 30 }" 
}; 

Per impostazione predefinita, Json.NET sarà serializzare questo oggetto come questo:

{ 
    "FirstName": "John", 
    "LastName": "Smith", 
    "Json": "{ \"Age\": 30 }" 
} 

mi piacerebbe essere in grado di istruire Json.NET presuppone che la proprietà Json sia già una rappresentazione serializzata, quindi non dovrebbe ricalibrare e il JSON risultante dovrebbe apparire così:

{ 
    "FirstName": "John", 
    "LastName": "Smith", 
    "Json": { 
     "Age": 30 
    } 
} 

Idealmente questo funziona in entrambe le direzioni, vale a dire quando POST la rappresentazione JSON verrà deserializzato automaticamente alla rappresentazione C# sopra.

Qual è il miglior meccanismo per raggiungere questo obiettivo con Json.NET? Ho bisogno di una personalizzazione JsonConverter? Esiste un meccanismo basato su attributi più semplice? L'efficienza conta; l'intero punto è saltare l'overhead di serializzazione, che potrebbe essere un po 'una micro-ottimizzazione, ma per ragioni di discussione, supponiamo che non lo sia. (Ci saranno potenzialmente essere grandi liste con ingombranti Json proprietà da restituire.)

+0

Se la proprietà 'Json' è una stringa, deve essere serializzata come stringa. Non sono completamente sicuro di quale sia il problema. Basta serializzarlo come una stringa, memorizzarla nel tuo database come una stringa e deserializzarla come una stringa. –

+0

Forse non l'ho spiegato bene. Ho aggiunto un campione JSON extra per evidenziare la differenza tra ciò che accade di default e ciò che sto cercando di ottenere. –

+1

Se il codice lato server sta ottenendo la stringa JSON da qualche parte che è possibile controllare, sarebbe molto meglio risolvere quella parte del problema piuttosto che cercare di ottenere una risoluzione per questo. Tuttavia, se proviene da qualcosa a cui non si ha accesso, il mio primo tentativo sarebbe di deserializzarlo quando lo si ottiene da qualunque origine lo si recuperi. Questo potrebbe essere fatto con un deserializzatore personalizzato. Non ci sono abbastanza informazioni per trovare la soluzione migliore per te. – krillgar

risposta

13

Se si è in grado di cambiare il tipo di proprietà Json su Personstring-JRaw allora si otterrà il risultato desiderato.

public class Person 
{ 
    public string FirstName { get; set;} 
    public string LastName { get; set;}   
    public JRaw Json { get; set;} 
} 

alternativa, è possibile mantenere la proprietà string, e aggiungere una proprietà JRaw da utilizzare come proxy per la serializzazione:

public class Person 
{ 
    public string FirstName { get; set;} 
    public string LastName { get; set;} 
    [JsonIgnore] 
    public string Json { get; set; } 

    [JsonProperty("Json")] 
    private JRaw MyJson 
    { 
     get { return new JRaw(this.Json); } 
     set { this.Json = value.ToString(); } 
    }   
} 

In entrambi i casi, sia la serializzazione e deserializzazione funzioneranno come hai richiesto .

+2

Non sapevo di 'JRaw' e sembra essere il più adatto per quello che sto cercando di risolvere. Grazie. –

+0

FWIW, a causa di questa risposta, penso che questa domanda dovrebbe essere quella che le altre domande "già poste" fanno riferimento. – HeyZiko

1

Non sono sicuro che questo è esattamente una cosa utile da fare, ma è possibile creare un convertitore personalizzato come questo:

public class StringToJsonConverter : JsonConverter 
{ 
    public override bool CanConvert(Type t) 
    { 
     throw new NotImplementedException(); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var o = JsonConvert.DeserializeObject(value.ToString()); 
     serializer.Serialize(writer,o); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     var o = serializer.Deserialize(reader); 
     return JsonConvert.SerializeObject(o); 
    } 
} 

ora se si decorare Json proprietà con [JsonConverter(typeof(StringToJsonConverter))], si può fare questo:

var obj = new Person 
{ 
    FirstName = "John", 
    LastName = "Smith", 
    Json = "{ \"Age\": 30 }" 
}; 

var s = JsonConvert.SerializeObject(obj); 

E ottenere questo:

{"FirstName":"John","LastName":"Smith","Json":{"Age":30}} 

Ecco una nota fiddle

Uno tuttavia a mio violino, sto giro inciampare la serializzazione e deserializzazione, ma i valori nella proprietà Json non sono esattamente la stessa cosa. Perché? Perché gli spazi extra intorno alle parentesi graffe sono stati eliminati nel processo. Certo, non sono (o non dovrebbero essere) significativi.

+0

L'attenzione degli elettori va spiegata? Raggiunge esattamente ciò che l'OP chiedeva. –

+0

Posso dirti che non ero io :) –

+0

Che ha funzionato (+1). Ma a questo punto, sto cominciando a dubitare dell'utilità. Poiché la proprietà deve solo esistere come stringa sul server, dalla richiesta non elaborata al database e viceversa, speravo in una soluzione che non prevedesse affatto la serializzazione/deserializzazione. Ma come proprietà di un oggetto genitore sto iniziando a pensare che non è possibile o non ne vale la pena. –

0

Non sono sicuro che sia possibile saltare la sequenza di serializzazione. Ecco un'opzione per serializzare e deserializzare in un modo semplice.

public class Person 
{ 
    public string FirstName = "John"; 
    public string LastName = "Smith"; 
    [JsonIgnore] 
    public string Json = "{ \"Age\": 30 }"; 
    public JObject JsonP { get { return JsonConvert.DeserializeObject<JObject>(Json); } } 
} 
Problemi correlati