Cómo excluir propiedades de la serialización Json


235

Tengo una clase DTO que serializo

Json.Serialize(MyClass)

¿Cómo puedo excluir una propiedad pública de la misma?

(Tiene que ser público, ya que lo uso en mi código en otro lugar)


44
¿Qué marco de serialización utilizas?
Pavel Gatilov

37
IgnoreDataMember ScriptIgnore JsonIgnoredependiendo del serializador que use
LB

3
También es digno de mención el atributo [No serializado], que solo es aplicable a los campos (no a las propiedades), pero que tiene el mismo efecto que JsonIgnore.
Triynko

El comentario de Trynko es muy útil ... si usa IgnoreDataMember en un campo, no habrá ningún error, pero no se aplicará.
Tillito

Respuestas:


147

Si está utilizando System.Web.Script.Serializationen .NET Framework , puede poner un ScriptIgnoreatributo en los miembros que no se debe serializar. Vea el ejemplo tomado de aquí :

Considere el siguiente caso (simplificado):

public class User {
    public int Id { get; set; }
    public string Name { get; set; }
    [ScriptIgnore]
    public bool IsComplete
    {
        get { return Id > 0 && !string.IsNullOrEmpty(Name); }
    } 
} 

En este caso, solo se serializarán las propiedades Id y Nombre, por lo que el objeto JSON resultante se vería así:

{ Id: 3, Name: 'Test User' }

PD. No olvide agregar una referencia a " System.Web.Extensions" para que esto funcione


10
Encontré ScriptIgnoreen el System.Web.Script.Serializationespacio de nombres.
Sorangwala Abbasali

354

Si está utilizando el atributo Json.Net[JsonIgnore] , simplemente ignorará el campo / propiedad mientras se serializa o deserializa.

public class Car
{
  // included in JSON
  public string Model { get; set; }
  public DateTime Year { get; set; }
  public List<string> Features { get; set; }

  // ignored
  [JsonIgnore]
  public DateTime LastModified { get; set; }
}

O puede usar el atributo DataContract y DataMember para serializar / deserializar selectivamente propiedades / campos.

[DataContract]
public class Computer
{
  // included in JSON
  [DataMember]
  public string Name { get; set; }
  [DataMember]
  public decimal SalePrice { get; set; }

  // ignored
  public string Manufacture { get; set; }
  public int StockCount { get; set; }
  public decimal WholeSalePrice { get; set; }
  public DateTime NextShipmentDate { get; set; }
}

Consulte http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size para obtener más detalles


37
Si yo fuera el OP, preferiría esta respuesta sobre la solución elegida [ScriptIgnore]. Principalmente debido a la congruencia de una solución Json, por lo que es un problema Json. ¿Por qué involucrar System.Web.Extensions cuando la biblioteca que está utilizando proporciona una solución? El mejor en mi humilde opinión es el atributo [IgnoreDataMember], ya que System.Runtime.Serialization debería ser compatible con todos los serializadores en caso de que desee cambiar Json.
Steve H.

IgnoreDataMemberno funciona con el JsonResultserializador predeterminado .
hendryanw

1
NewtonSoft me ayudó completamente. Hizo que mi json se vea limpio sin que se incluyeran propiedades desordenadas de mis modelos que son solo para backend.
Sorangwala Abbasali

1
@JC Raja ¿Cómo puedo ignorar la propiedad durante la desalinización solo cuando esta propiedad es nula
User123456

1
[NewtonSoft.Json] Quiero ignorar solo la serialización. Entonces, ¿alguna solución para esto?
Trương Quốc Khánh

31

Puedes usar [ScriptIgnore]:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    [ScriptIgnore]
    public bool IsComplete
    {
        get { return Id > 0 && !string.IsNullOrEmpty(Name); }
    }
}

Referencia aquí

En este caso, el Id y el nombre solo se serializarán


1
La URL en su respuesta está rota. ¿ [ScriptIgnore]Qué debe usarse en la propiedad si su controlador está usando el controlador MVC base return Json(...?
Don Cheadle

2
Sé que es un comentario antiguo, pero sí, utilícelo [ScriptIgnore]en MVC Controller. Sin embargo, tenga en cuenta que si está utilizando SignalR , también debería usarlo [JsonIgnore].
Sam

22

Lo siento, decidí escribir otra respuesta ya que ninguna de las otras respuestas es lo suficientemente pegable.

Si no desea decorar propiedades con algunos atributos, o si no tiene acceso a la clase, o si desea decidir qué serializar durante el tiempo de ejecución, etc., etc., así es como lo hace en Newtonsoft.Json

//short helper class to ignore some properties from serialization
public class IgnorePropertiesResolver : DefaultContractResolver
{
    private IEnumerable<string> _propsToIgnore;
    public IgnorePropertiesResolver(IEnumerable<string> propNamesToIgnore)
    {
        _propsToIgnore = propNamesToIgnore;
    }
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);
        property.ShouldSerialize = (x) => { return !_propsToIgnore.Contains(property.PropertyName); };
        return property;
    }
}

Uso

JsonConvert.SerializeObject(YourObject, new JsonSerializerSettings()
    { ContractResolver = new IgnorePropertiesResolver(new[] { "Prop1", "Prop2" }) };);

He publicado el código aquí en caso de que alguien quiera agregar algo

https://github.com/jitbit/JsonIgnoreProps

ACTUALIZACIÓN IMPORTANTE: asegúrese de guardar en caché el ContractResolverobjeto si decide usar esta respuesta, de lo contrario, el rendimiento puede verse afectado.


15

Si no está tan interesado en tener que decorar el código con Atributos como yo, especialmente cuando no puede decir en tiempo de compilación lo que sucederá aquí es mi solución.

Usando el serializador Javascript

    public static class JsonSerializerExtensions
    {
        public static string ToJsonString(this object target,bool ignoreNulls = true)
        {
            var javaScriptSerializer = new JavaScriptSerializer();
            if(ignoreNulls)
            {
                javaScriptSerializer.RegisterConverters(new[] { new PropertyExclusionConverter(target.GetType(), true) });
            }
            return javaScriptSerializer.Serialize(target);
        }

        public static string ToJsonString(this object target, Dictionary<Type, List<string>> ignore, bool ignoreNulls = true)
        {
            var javaScriptSerializer = new JavaScriptSerializer();
            foreach (var key in ignore.Keys)
            {
                javaScriptSerializer.RegisterConverters(new[] { new PropertyExclusionConverter(key, ignore[key], ignoreNulls) });
            }
            return javaScriptSerializer.Serialize(target);
        }
    }


public class PropertyExclusionConverter : JavaScriptConverter
    {
        private readonly List<string> propertiesToIgnore;
        private readonly Type type;
        private readonly bool ignoreNulls;

        public PropertyExclusionConverter(Type type, List<string> propertiesToIgnore, bool ignoreNulls)
        {
            this.ignoreNulls = ignoreNulls;
            this.type = type;
            this.propertiesToIgnore = propertiesToIgnore ?? new List<string>();
        }

        public PropertyExclusionConverter(Type type, bool ignoreNulls)
            : this(type, null, ignoreNulls){}

        public override IEnumerable<Type> SupportedTypes
        {
            get { return new ReadOnlyCollection<Type>(new List<Type>(new[] { this.type })); }
        }

        public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
        {
            var result = new Dictionary<string, object>();
            if (obj == null)
            {
                return result;
            }
            var properties = obj.GetType().GetProperties();
            foreach (var propertyInfo in properties)
            {
                if (!this.propertiesToIgnore.Contains(propertyInfo.Name))
                {
                    if(this.ignoreNulls && propertyInfo.GetValue(obj, null) == null)
                    {
                         continue;
                    }
                    result.Add(propertyInfo.Name, propertyInfo.GetValue(obj, null));
                }
            }
            return result;
        }

        public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
        {
            throw new NotImplementedException(); //Converter is currently only used for ignoring properties on serialization
        }
    }

1
Un cambio menor en la lógica y PropertyExclusionConverterse puede convertir en a PropertyInclusionConverter.
Zarepheth

esto es simplemente increíble
SaiKiran Mandhala

Un problema potencial con esto es que tiene que hacer el trabajo de coincidencia de nombres y exclusión una y otra vez cada vez que se serializa un objeto. Sin embargo, una vez compilado, las propiedades de un tipo no cambiarán; debe hacer este cálculo previo, por tipo, de los nombres que deben incluirse y simplemente reutilizar la lista en cada fila. Para un trabajo de serialización JSON muy masivo, el almacenamiento en caché podría marcar una diferencia notable en el rendimiento.
ErikE

9

Si está usando, System.Text.Jsonentonces puede usar [JsonIgnore].
FQ:System.Text.Json.Serialization.JsonIgnoreAttribute

Documentos oficiales de Microsoft: JsonIgnoreAttribute

Como se indica aquí :

La biblioteca está integrada como parte del marco compartido .NET Core 3.0.
Para otros marcos de destino, instale el paquete System.Text.Json NuGet. El paquete admite:

  • .NET Standard 2.0 y versiones posteriores
  • .NET Framework 4.6.1 y versiones posteriores
  • .NET Core 2.0, 2.1 y 2.2

0

También puedes usar el [NonSerialized]atributo

[Serializable]
public struct MySerializableStruct
{
    [NonSerialized]
    public string hiddenField;
    public string normalField;
}

De los documentos de MS :

Indica que un campo de una clase serializable no debe serializarse. Esta clase no puede heredarse.


Si está utilizando Unity, por ejemplo ( esto no es solo para Unity ), entonces esto funciona conUnityEngine.JsonUtility

using UnityEngine;

MySerializableStruct mss = new MySerializableStruct 
{ 
    hiddenField = "foo", 
    normalField = "bar" 
};
Debug.Log(JsonUtility.ToJson(mss)); // result: {"normalField":"bar"}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.