Jak wykluczyć właściwość z serializacji Json

234

Mam klasę DTO, którą szereguję

Json.Serialize(MyClass)

Jak mogę wykluczyć jego własność publiczną ?

(Musi być publiczny, ponieważ używam go w kodzie gdzie indziej)

Elad Benda
źródło
4
Z jakich ram serializacji korzystasz?
Pavel Gatilov
37
IgnoreDataMember ScriptIgnore JsonIgnorew zależności od używanego serializatora
LB
3
na uwagę zasługuje również atrybut [NonSerialized], który ma zastosowanie tylko do pól (nie właściwości), ale poza tym ma taki sam efekt jak JsonIgnore.
Triynko
Komentarz Trynko jest bardzo przydatny .... jeśli użyjesz IgnoreDataMember na polu, nie będzie błędu, ale nie zostanie zastosowany.
Tillito,

Odpowiedzi:

147

Jeśli używasz System.Web.Script.Serializationw środowisku .NET , możesz nadać ScriptIgnoreczłonkom atrybut, którego nie należy szeregować. Zobacz przykład wzięty stąd :

Rozważ następujący (uproszczony) przypadek:

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

W takim przypadku tylko właściwości Id i Nazwa zostaną przekształcone do postaci szeregowej, dlatego wynikowy obiekt JSON będzie wyglądał następująco:

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

PS. Nie zapomnij dodać odniesienia do „ System.Web.Extensions”, aby to zadziałało

Pavel Krymets
źródło
10
Znalazłem ScriptIgnorew System.Web.Script.Serializationprzestrzeni nazw.
Sorangwala Abbasali
354

Jeśli używasz atrybutu Json.Net[JsonIgnore] , po prostu zignorujesz pole / właściwość podczas serializacji lub deserializacji.

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

Lub możesz użyć atrybutu DataContract i DataMember do selektywnej serializacji / deserializacji właściwości / pól.

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

Patrz http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size więcej szczegółów

JC Raja
źródło
37
Gdybym był OP, wolałbym tę odpowiedź niż wybrane rozwiązanie [ScriptIgnore]. Przede wszystkim ze względu na zgodność rozwiązania Json z problemem Json. Po co angażować System.Web.Extensions, gdy używana biblioteka zapewnia rozwiązanie? Absolutnie najlepszym IMHO jest atrybut [IgnoreDataMember], ponieważ System.Runtime.Serialization powinien być kompatybilny z każdym serializatorem, jeśli chcesz zamienić Jsona.
Steve H.
IgnoreDataMembernie działa z domyślnym JsonResultserializatorem.
hendryanw,
1
NewtonSoft pomógł mi w pełni. To sprawiło, że mój json wyglądał czysto, bez żadnych nieporządnych właściwości z moich modeli, które są tylko dla backendu.
Sorangwala Abbasali
1
@JC Raja Jak mogę zignorować właściwość podczas odsalania tylko wtedy, gdy ta właściwość jest pusta
24.04.17
1
[NewtonSoft.Json] Chcę zignorować tylko serializację. Jakieś rozwiązanie tego problemu?
Trương Quốc Khánh
31

Możesz użyć [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); }
    }
}

Odnośnik tutaj

W takim przypadku identyfikator, a następnie nazwa będą tylko serializowane

Arion
źródło
1
Adres URL w odpowiedzi jest uszkodzony. Czy [ScriptIgnore]należy korzystać z właściwości, jeśli kontroler korzysta z podstawowego kontrolera MVC return Json(...?
Don Cheadle
2
Wiem, że to stary komentarz, ale tak, użyj [ScriptIgnore]w MVC Controller. Pamiętaj jednak, że jeśli używasz SignalR , powinieneś [JsonIgnore]również użyć .
Sam
21

Przepraszamy, postanowiłem napisać inną odpowiedź, ponieważ żadnej z pozostałych odpowiedzi nie można wystarczająco wkleić.

Jeśli nie chcesz dekorować właściwości za pomocą niektórych atrybutów lub jeśli nie masz dostępu do klasy, lub jeśli chcesz zdecydować, co do serializacji w czasie wykonywania itp. Itp., Oto jak to zrobić w 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;
    }
}

Stosowanie

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

Opublikowałem tutaj kod na wypadek, gdyby ktoś chciał coś dodać

https://github.com/jitbit/JsonIgnoreProps

WAŻNA AKTUALIZACJA: upewnij się, że buforujesz ContractResolverobiekt, jeśli zdecydujesz się użyć tej odpowiedzi, w przeciwnym razie może to pogorszyć wydajność.

Alex
źródło
15

Jeśli nie lubisz dekorować kodu atrybutami tak, jak ja, szczególnie gdy nie możesz powiedzieć w czasie kompilacji, co się tutaj stanie, to moje rozwiązanie.

Korzystanie z Serializatora 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
        }
    }
Thulani Chivandikwa
źródło
1
Niewielka zmiana w logice i PropertyExclusionConvertermoże być przekształcona w PropertyInclusionConverter.
Zarepheth,
to jest po prostu niesamowite
SaiKiran Mandhala,
Jednym z potencjalnych problemów jest to, że musi on ciągle dopasowywać nazwy i wykluczać za każdym razem, gdy obiekt jest szeregowany. Jednak po skompilowaniu właściwości typu nie zmienią się - należy wstępnie obliczyć dla każdego typu nazwy, które należy uwzględnić, i po prostu ponownie użyć listy w każdym wierszu. W przypadku bardzo masowego zadania serializacji JSON buforowanie może mieć zauważalną różnicę w wydajności.
ErikE
9

Jeśli używasz System.Text.Json, możesz użyć [JsonIgnore].
FQ:System.Text.Json.Serialization.JsonIgnoreAttribute

Oficjalne dokumenty Microsoft: JsonIgnoreAttribute

Jak stwierdzono tutaj :

Biblioteka jest wbudowana jako część wspólnego środowiska .NET Core 3.0.
W przypadku innych platform docelowych zainstaluj pakiet System.Text.Json NuGet. Pakiet obsługuje:

  • .NET Standard 2.0 i nowsze wersje
  • .NET Framework 4.6.1 i nowsze wersje
  • .NET Core 2.0, 2.1 i 2.2
Travis
źródło
0

Możesz także użyć [NonSerialized]atrybutu

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

Z dokumentów MS :

Wskazuje, że pole klasy możliwej do serializacji nie powinno być serializowane. Ta klasa nie może być dziedziczona.


Jeśli używasz na przykład Unity ( nie dotyczy to tylko Unity ), to działa zUnityEngine.JsonUtility

using UnityEngine;

MySerializableStruct mss = new MySerializableStruct 
{ 
    hiddenField = "foo", 
    normalField = "bar" 
};
Debug.Log(JsonUtility.ToJson(mss)); // result: {"normalField":"bar"}
Tak Barry
źródło