Json.NET – предотвратить повторное сериализацию уже сериализованного свойства

В приложении ASP.NET Web API некоторые из моделей, с которыми я работаю, содержат кусок ad-hoc JSON, который полезен только на стороне клиента. На сервере он просто входит и выходит из реляционной базы данных в виде строки. Производительность является ключевой, и кажется бессмысленным обрабатывать серверный сервер JSON вообще.

Итак, в C #, представьте себе такой объект:

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

По умолчанию Json.NET будет сериализовать этот объект следующим образом:

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

Я хотел бы дать указание Json.NET предположить, что свойство Json уже является сериализованным представлением, поэтому его не следует повторно сериализовать, и полученный JSON должен выглядеть следующим образом:

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

В идеале это работает в обоих направлениях, то есть когда POSTing представление JSON будет автоматически десериализоваться в представлении C # выше.

Каков наилучший механизм для достижения этого с помощью Json.NET? Мне нужен пользовательский JsonConverter ? Существует ли более простой механизм, основанный на атрибутах? Эффективность имеет значение; все дело в том, чтобы пропустить накладные расходы на сериализацию, что может быть немного микро-оптимизацией, но, ради аргумента, предположим, что это не так. ( Json будут большие списки с Json массивных свойств Json .)

Если вы можете изменить тип свойства Json на Person из string в JRaw вы получите желаемый результат.

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

Кроме того, вы можете сохранить свойство string и добавить свойство JRaw которое будет использоваться в качестве прокси для сериализации:

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

В любом случае, как сериализация, так и десериализация будут работать по вашему запросу.

Я не уверен, что это очень полезная вещь, но вы можете создать собственный конвертер следующим образом:

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

Теперь, если вы Json свойство Json с помощью [JsonConverter(typeof(StringToJsonConverter))] , вы можете сделать это:

 var obj = new Person { FirstName = "John", LastName = "Smith", Json = "{ \"Age\": 30 }" }; var s = JsonConvert.SerializeObject(obj); 

И получите следующее:

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

Вот скрипка

Одна нота, однако, в моей скрипке, я кругом отключаю сериализацию и десериализацию, но значения в свойстве Json не совсем то же самое. Зачем? Потому что лишние пространства вокруг ваших фигурных скобок были устранены в процессе. Конечно, они не являются (или не должны быть) значительными.

Я не уверен, что есть способ пропустить сериализацию. Вот вариант сериализации и десериализации в простой форме.

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