如何从ASP.NET Web API模型中过滤掉具有0个元素的数组对象。
Ex:我正在使用以下方法来过滤空对象。
using Newtonsoft.Json;
public string FaxWork { get; set; }
[JsonProperty(PropertyName = "phoneWork", NullValueHandling = NullValueHandling.Ignore)]
如何使用上面的内容来过滤掉[]
空数组对象?
例如:
"postalAddress": [],
"electronicAddress": []
答案 0 :(得分:2)
您可以使用Json.NET的conditional property serialization功能完成此操作。
如果您只想在数组值为空时忽略单个成员,请在您不希望序列化时返回ShouldSerialize{PropertyName}()
的类中添加false
方法,例如:
public class RootObject
{
public string[] PostalAddress { get; set; }
public bool ShouldSerializePostalAddress() { return PostalAddress != null && PostalAddress.Length > 0; }
}
如果您需要为许多不同类型的许多不同的集合值成员执行此操作,您可以创建一个custom contract resolver,为所有这些成员自动生成ShouldSerialize
谓词:
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();
}
}
}
然后使用JsonSerializerSettings
进行序列化,如下所示,这也可以启用名称的驼峰外壳:
var settings = new JsonSerializerSettings
{
ContractResolver = new SkipEmptyCollectionsContractResolver { NamingStrategy = new CamelCaseNamingStrategy() },
NullValueHandling = NullValueHandling.Ignore,
};
如果您想使用属性有条件地过滤掉空集合,可以使用以下合约解析程序和属性来执行此操作:
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;
}
}
然后按以下方式向您的会员申请:
public class RootObject
{
[JsonPropertyExtensions(EmptyArrayHandling = EmptyArrayHandling.Ignore)]
public string[] PostalAddress { get; set; }
}
请注意,如果您的“集合”实际上是一个复杂的LINQ查询,ShouldSerialize
方法将必须枚举查询的第一个元素以查看它是否为空,这可能会导致性能不佳,因为查询将被评估两次。为避免这种情况,您可以在序列化之前将整个查询评估为列表。
您可能需要cache the contract resolver才能获得最佳效果。