Hacer que una propiedad se deserialice pero no se serialice con json.net

Resuelto Will Dean asked hace 12 años • 14 respuestas

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 ser una simple propiedad de enumeración a una propiedad de clase.

Una forma sencilla de hacer esto sería dejar la antigua propiedad enum en la clase y hacer que Json.net lea esta propiedad cuando carguemos la configuración, pero no la guarde nuevamente la próxima vez que serialicemos el objeto. Nos ocuparemos de generar la nueva clase a partir de la enumeración anterior por separado.

¿Existe alguna forma sencilla de marcar (por ejemplo, con atributos) una propiedad de un objeto C#, de modo que Json.net la ignore SÓLO al serializar, pero la preste atención al deserializar?

Will Dean avatar Jul 19 '12 22:07 Will Dean
Aceptado

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

Supongamos, por ejemplo, que actualmente tiene sus clases definidas de esta manera:

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 conseguir esto:

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

Método 1: agregar un método ShouldSerialize

Json.NET tiene la capacidad de serializar propiedades condicionalmente buscando los ShouldSerializemétodos correspondientes en la clase.

Para utilizar esta función, agregue un método booleano ShouldSerializeBlah()a su clase donde Blahse reemplace con el nombre de la propiedad que no desea serializar. Haga que la implementación de este método siempre regrese 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 enturbiar la interfaz pública de tu clase introduciendo un ShouldSerializemétodo, puedes usar un IContractResolverpara hacer lo mismo mediante programación. Consulte Serialización de propiedad condicional en la documentación.

Enfoque 2: manipular el JSON con JObjects

En lugar de usarlo JsonConvert.SerializeObjectpara realizar la serialización, cargue el objeto de configuración en un archivo JObjecty luego simplemente elimine la propiedad no deseada del JSON antes de escribirlo. Son sólo 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: (ab)uso inteligente de atributos

  1. Aplique un [JsonIgnore]atributo a la propiedad que no desea que se serialice.
  2. Agregue un definidor de propiedad privada 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 [JsonProperty]atributo al definidor alternativo, dándole el mismo nombre JSON que la propiedad original.

ConfigAquí está la clase 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; }
}
Brian Rogers avatar Jun 14 '2014 21:06 Brian Rogers

Para cualquier situación en la que sea aceptable marcar la propiedad de solo deserialización como interna, existe una solución notablemente simple que no depende en absoluto de los atributos. Simplemente marque la propiedad como obtención interna, pero como conjunto público:

public class JsonTest {

    public string SomeProperty { internal get; set; }

}

Esto da como resultado una deserialización correcta utilizando la configuración/resolución/etc. predeterminada, pero la propiedad se elimina de la salida serializada.

Iucounu avatar Feb 27 '2018 18:02 Iucounu

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

PASO 1: cree el atributo personalizado

public class JsonIgnoreSerializationAttribute : Attribute { }

PASO 2: cree un contrato reslover 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: agregue un atributo donde la serialización no sea necesaria pero sí la deserialización.

    [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 ocurre la deserialización, cuando estoy deserializando simplemente uso el convertidor de la manera convencional.

JsonConvert.DeserializeObject<MyType>(myString);
Jraco11 avatar Feb 05 '2016 22:02 Jraco11

Utilice la propiedad de establecimiento:

[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.

Tho Ho avatar Jun 13 '2014 10:06 Tho Ho