c# json.net

c# - Hacer una propiedad deserializar pero no serializar con json.net



(7)

Tenemos algunos archivos de configuración que se generaron al serializar objetos C # con Json.net.

Nos gustaría migrar una propiedad de la clase serializada de una simple propiedad enum a una propiedad de clase.

Una forma fácil de hacerlo sería dejar la propiedad enum antigua en la clase y hacer que Json.net lea esta propiedad cuando cargamos la configuración, pero no volver a guardarla la próxima vez que serialicemos el objeto. Trataremos de generar la nueva clase de la vieja enumeración por separado.

¿Hay alguna manera simple de marcar (por ejemplo, con atributos) una propiedad de un objeto C #, de modo que Json.net lo ignore ÚNICAMENTE al serializarlo, pero preste atención cuando deserialice?


Después de que pasé un tiempo bastante largo buscando cómo marcar una propiedad de clase para ser De-Serializable y NO Serializable, descubrí que no existe tal cosa para hacer eso; así que se me ocurrió una solución que combina dos bibliotecas diferentes o técnicas de serialización (System.Runtime.Serialization.Json & Newtonsoft.Json) y funcionó para mí de la siguiente manera:

  • marque todas sus clases y subclases como "DataContract".
  • marque todas las propiedades de su clase y subclases como "DataMember".
  • marque todas las propiedades de su clase y subclases como "JsonProperty", excepto las que desee que no se serialicen.
  • ahora marque las propiedades que NO quiere que se serialicen como "JsonIgnore".
  • luego serializar usando "Newtonsoft.Json.JsonConvert.SerializeObject" y De-Serialize usando "System.Runtime.Serialization.Json.DataContractJsonSerializer".

    using System; using System.Collections.Generic; using Newtonsoft.Json; using System.Runtime.Serialization; using System.IO; using System.Runtime.Serialization.Json; using System.Text; namespace LUM_Win.model { [DataContract] public class User { public User() { } public User(String JSONObject) { MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(JSONObject)); DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(User)); User user = (User)dataContractJsonSerializer.ReadObject(stream); this.ID = user.ID; this.Country = user.Country; this.FirstName = user.FirstName; this.LastName = user.LastName; this.Nickname = user.Nickname; this.PhoneNumber = user.PhoneNumber; this.DisplayPicture = user.DisplayPicture; this.IsRegistred = user.IsRegistred; this.IsConfirmed = user.IsConfirmed; this.VerificationCode = user.VerificationCode; this.Meetings = user.Meetings; } [DataMember(Name = "_id")] [JsonProperty(PropertyName = "_id")] public String ID { get; set; } [DataMember(Name = "country")] [JsonProperty(PropertyName = "country")] public String Country { get; set; } [DataMember(Name = "firstname")] [JsonProperty(PropertyName = "firstname")] public String FirstName { get; set; } [DataMember(Name = "lastname")] [JsonProperty(PropertyName = "lastname")] public String LastName { get; set; } [DataMember(Name = "nickname")] [JsonProperty(PropertyName = "nickname")] public String Nickname { get; set; } [DataMember(Name = "number")] [JsonProperty(PropertyName = "number")] public String PhoneNumber { get; set; } [DataMember(Name = "thumbnail")] [JsonProperty(PropertyName = "thumbnail")] public String DisplayPicture { get; set; } [DataMember(Name = "registered")] [JsonProperty(PropertyName = "registered")] public bool IsRegistred { get; set; } [DataMember(Name = "confirmed")] [JsonProperty(PropertyName = "confirmed")] public bool IsConfirmed { get; set; } [JsonIgnore] [DataMember(Name = "verification_code")] public String VerificationCode { get; set; } [JsonIgnore] [DataMember(Name = "meeting_ids")] public List<Meeting> Meetings { get; set; } public String toJSONString() { return JsonConvert.SerializeObject(this, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore }); } } }

Espero que ayude ...


En realidad, hay varios enfoques bastante simples que puede utilizar para lograr el resultado que desea.

Supongamos, por ejemplo, que sus clases actualmente se definen así:

class Config { public Fizz ObsoleteSetting { get; set; } public Bang ReplacementSetting { get; set; } } enum Fizz { Alpha, Beta, Gamma } class Bang { public string Value { get; set; } }

Y quieres hacer esto:

string json = @"{ ""ObsoleteSetting"" : ""Gamma"" }"; // deserialize Config config = JsonConvert.DeserializeObject<Config>(json); // migrate config.ReplacementSetting = new Bang { Value = config.ObsoleteSetting.ToString() }; // serialize json = JsonConvert.SerializeObject(config); Console.WriteLine(json);

Para obtener esto:

{"ReplacementSetting":{"Value":"Gamma"}}

Método 1: agregue un método ShouldSerialize

Json.NET tiene la capacidad de serializar de forma condicional las propiedades buscando los métodos ShouldSerialize correspondientes en la clase.

Para usar esta función, agregue un método ShouldSerializeBlah() a su clase donde Blah se reemplaza con el nombre de la propiedad que no desea serializar. Haga que la implementación de este método siempre devuelva false .

class Config { public Fizz ObsoleteSetting { get; set; } public Bang ReplacementSetting { get; set; } public bool ShouldSerializeObsoleteSetting() { return false; } }

Nota: si te gusta este enfoque pero no quieres ensuciar la interfaz pública de tu clase al introducir un método ShouldSerialize , puedes usar IContractResolver para hacer lo mismo programáticamente. Consulte Serialización condicional de propiedades en la documentación.

Enfoque 2: Manipule el JSON con JObjects

En lugar de usar JsonConvert.SerializeObject para hacer la serialización, cargue el objeto de configuración en JObject , luego simplemente elimine la propiedad no deseada de JSON antes de escribirla. Es solo un par de líneas adicionales de código.

JObject jo = JObject.FromObject(config); // remove the "ObsoleteSetting" JProperty from its parent jo["ObsoleteSetting"].Parent.Remove(); json = jo.ToString();

Enfoque 3: uso inteligente (ab) de los atributos

  1. Aplique un atributo [JsonIgnore] a la propiedad que no desea serializar.
  2. Agregue un instalador de propiedades privado alternativo a la clase con el mismo tipo que la propiedad original. Haga que la implementación de esa propiedad establezca la propiedad original.
  3. Aplique un atributo [JsonProperty] al setter alternativo, dándole el mismo nombre JSON que la propiedad original.

Aquí está la clase de Config revisada:

class Config { [JsonIgnore] public Fizz ObsoleteSetting { get; set; } [JsonProperty("ObsoleteSetting")] private Fizz ObsoleteSettingAlternateSetter { // get is intentionally omitted here set { ObsoleteSetting = value; } } public Bang ReplacementSetting { get; set; } }


Me gusta seguir con los atributos en este caso, aquí está el método que uso cuando necesito deserializar una propiedad pero no serializarla o viceversa.

PASO 1 - Crea el atributo personalizado

public class JsonIgnoreSerializationAttribute : Attribute { }

PASO 2: cree un reslover de contrato personalizado

class JsonPropertiesResolver : DefaultContractResolver { protected override List<MemberInfo> GetSerializableMembers(Type objectType) { //Return properties that do NOT have the JsonIgnoreSerializationAttribute return objectType.GetProperties() .Where(pi => !Attribute.IsDefined(pi, typeof(JsonIgnoreSerializationAttribute))) .ToList<MemberInfo>(); } }

PASO 3 - Agregar atributo donde la serialización no es necesaria pero la deserialización es

[JsonIgnoreSerialization] public string Prop1 { get; set; } //Will be skipped when serialized [JsonIgnoreSerialization] public string Prop2 { get; set; } //Also will be skipped when serialized public string Prop3 { get; set; } //Will not be skipped when serialized

PASO 4: Úselo

var sweet = JsonConvert.SerializeObject(myObj, new JsonSerializerSettings { ContractResolver = new JsonPropertiesResolver() });

¡Espero que esto ayude! También vale la pena señalar que esto también ignorará las propiedades cuando ocurra la Deserialización, cuando estoy deserializando simplemente uso el convertidor de la manera convencional.

JsonConvert.DeserializeObject<MyType>(myString);


Para construir sobre la respuesta de Tho Ho, esto también se puede usar para campos.

[JsonProperty(nameof(IgnoreOnSerializing))] public string IgnoreOnSerializingSetter { set { IgnoreOnSerializing = value; } } [JsonIgnore] public string IgnoreOnSerializing;


Para cualquier situación en la que sea aceptable que su propiedad exclusiva de deserialización se marque como interna, existe una solución notablemente simple que no depende en absoluto de los atributos. Simplemente marque la propiedad como get interno, pero public set:

public class JsonTest { public string SomeProperty { internal get; set; } }

Esto da como resultado una deserialización correcta utilizando configuraciones / resolvedores / etc. Predeterminados, pero la propiedad se elimina de la salida serializada.


Usar la propiedad setter:

[JsonProperty(nameof(IgnoreOnSerializing))] public string IgnoreOnSerializingSetter { set { _ignoreOnSerializing = value; } } [JsonIgnore] private string _ignoreOnSerializing; [JsonIgnore] public string IgnoreOnSerializing { get { return this._ignoreOnSerializing; } set { this._ignoreOnSerializing = value; } }

Espero que esto ayude.


con referencia a la solución de @ ThoHo, usar setter es todo lo que se necesita, sin etiquetas adicionales.

Para mí, anteriormente tenía un Id de referencia único, que quería cargar y agregar a la nueva colección de Ids de referencia. Al cambiar la definición del Id. De referencia para que solo contenga un método setter, que agregó el valor a la nueva colección. Json no puede escribir el valor de nuevo si la propiedad no tiene un get; método.

// Old property that I want to read from Json, but never write again. No getter. public Guid RefId { set { RefIds.Add(value); } } // New property that will be in use from now on. Both setter and getter. public ICollection<Guid> RefIds { get; set; }

Esta clase ahora es retrocompatible con la versión anterior y solo guarda los RefIds para las nuevas versiones.