2017-10-02 1 views
0

Comment puis-je filtrer les objets de tableau qui contiennent 0 éléments du modèle API Web ASP.NET. Ex: J'utilise la méthode ci-dessous pour filtrer les objets nuls.Validation de la réponse aux objets du tableau de filtres qui ne contiennent aucun élément

using Newtonsoft.Json; 

public string FaxWork { get; set; } 
[JsonProperty(PropertyName = "phoneWork", NullValueHandling = NullValueHandling.Ignore)] 

Comment puis-je utiliser quelque chose comme ci-dessus afin de filtrer [] objets tableau vide?

Ex:

"postalAddress": [], 
"electronicAddress": [] 
+0

Voulez-vous ignorer une seule propriété spécifique lorsque sa valeur est un tableau vide ou toutes ses propriétés globalement dans tous vos modèles? Si seulement pour une seule propriété, voir [Comment ignorer les champs et les propriétés conditionnellement lors de la sérialisation en utilisant JSON.Net?](https://stackoverflow.com/q/34304738). – dbc

Répondre

1

Vous pouvez y parvenir en utilisant la fonctionnalité conditional property serialization de Json.NET.

Si vous voulez juste d'ignorer un seul membre lorsque sa valeur de tableau est vide, ajoutez une méthode ShouldSerialize{PropertyName}() à votre classe qui retourne false quand vous ne voulez pas sérialisé, par exemple:

public class RootObject 
{ 
    public string[] PostalAddress { get; set; } 

    public bool ShouldSerializePostalAddress() { return PostalAddress != null && PostalAddress.Length > 0; } 
} 

Si vous besoin de faire cela pour de nombreux membres contenant des collections de nombreux types différents, vous pouvez créer un custom contract resolver qui génère automatiquement un prédicat ShouldSerialize pour tous alors:

public class SkipEmptyCollectionsContractResolver : DefaultContractResolver 
{ 
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) 
    { 
     var property = base.CreateProperty(member, memberSerialization) 
      .AddShouldSerializeEmptyCollections(this); 
     return property; 
    } 
} 

public static class JsonPropertyExtensions 
{ 
    public static JsonProperty AddShouldSerializeEmptyCollections(this JsonProperty property, IContractResolver resolver) 
    { 
     if (property == null) 
      throw new ArgumentNullException(); 
     if ((typeof(IEnumerable).IsAssignableFrom(property.PropertyType) || property.PropertyType.IsAssignableFrom(typeof(IEnumerable))) 
      && property.PropertyType != typeof(string) 
      && property.Readable) 
     { 
      Predicate<object> shouldSerialize = (parent) => 
      { 
       var value = property.ValueProvider.GetValue(parent); 
       if (value == null || value is string) 
        return true; // null properties are filtered by the NullValueHandling setting. 
       var contract = resolver.ResolveContract(value.GetType()); 
       if (contract is JsonArrayContract) 
       { 
        return (value as IEnumerable).Any(); 
       } 
       return true; 
      }; 
      var oldShouldSerialize = property.ShouldSerialize; 
      if (oldShouldSerialize == null) 
       property.ShouldSerialize = shouldSerialize; 
      else 
       property.ShouldSerialize = (o) => shouldSerialize(o) && oldShouldSerialize(o); 
     } 

     return property; 
    } 
} 

public static class EnumerableExtensions 
{ 
    public static bool Any(this IEnumerable enumerable) 
    { 
     if (enumerable == null) 
      return false; 
     if (enumerable is ICollection) 
     { 
      return ((ICollection)enumerable).Count > 0; 
     } 
     var enumerator = enumerable.GetEnumerator(); 
     using (enumerator as IDisposable) 
     { 
      return enumerator.MoveNext(); 
     } 
    } 
} 

puis seriali ze utilisant JsonSerializerSettings tels que les suivants, ce qui permet également boîtier de chameau des noms:

var settings = new JsonSerializerSettings 
{ 
    ContractResolver = new SkipEmptyCollectionsContractResolver { NamingStrategy = new CamelCaseNamingStrategy() }, 
    NullValueHandling = NullValueHandling.Ignore, 
}; 

Si vous souhaitez filtrer conditionnellement des collections vides à l'aide des attributs, vous pouvez le faire avec le résolveur contrat suivant et attribut:

public enum EmptyArrayHandling 
{ 
    Include = 0, 
    Ignore = 1, 
} 

[System.AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] 
public class JsonPropertyExtensionsAttribute : System.Attribute 
{ 
    public EmptyArrayHandling EmptyArrayHandling { get; set; } 
} 

public class ConditionallySkipEmptyCollectionsContractResolver : DefaultContractResolver 
{ 
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) 
    { 
     var property = base.CreateProperty(member, memberSerialization); 
     var attr = property.AttributeProvider.GetAttributes(typeof(JsonPropertyExtensionsAttribute), false).Cast<JsonPropertyExtensionsAttribute>().FirstOrDefault(); 
     if (attr != null && attr.EmptyArrayHandling == EmptyArrayHandling.Ignore) 
      property = property.AddShouldSerializeEmptyCollections(this); 
     return property; 
    } 
} 

Appliquez ensuite à vos membres comme suit:

public class RootObject 
{ 
    [JsonPropertyExtensions(EmptyArrayHandling = EmptyArrayHandling.Ignore)] 
    public string[] PostalAddress { get; set; } 
} 

Notez que si votre « collection » est en fait une requête LINQ complexe, ShouldSerialize méthode devra énumérer le premier élément de la requête pour voir si elle est vide, ce qui peut conduire à des performances médiocres, car la requête sera évaluée deux fois. Pour éviter cela, vous pouvez évaluer la requête entière sous la forme d'une liste avant la sérialisation.

Vous pouvez vouloir cache the contract resolver pour de meilleures performances.