最近项目中有一个比较特殊的需求,在返回给前端树形json数据时,将等于NULL和集合count等于0的设置为忽略序列化;由于返回数据中集合较多,一时间没有太好的方案,于是开始在递归方法中处理数据,将集合数据为空或集合为0的数据赋值为NULL,但是实践过程不是很理想,于是翻看一些资料。
首先,介绍一下Newtonsoft.Json:
方案一:
如果您正在寻找一种可以在不同类型中通用且不需要任何修改(属性等)的解决方案,那么我认为最好的解决方案是自定义DefaultContractResolver类。它将使用反射来确定IEnumerable给定类型的任何值是否为空,代码如下:
public class IgnoreEmptyEnumerablesResolver : DefaultContractResolver
{
public static readonly IgnoreEmptyEnumerablesResolver Instance = new IgnoreEmptyEnumerablesResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (property.PropertyType != typeof(string) &&
typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
{
property.ShouldSerialize = instance =>
{
IEnumerable enumerable = null;
// this value could be in a public field or public property
switch (member.MemberType)
{
case MemberTypes.Property:
enumerable = instance
.GetType()
.GetProperty(member.Name)
.GetValue(instance, null) as IEnumerable;
break;
case MemberTypes.Field:
enumerable = instance
.GetType()
.GetField(member.Name)
.GetValue(instance) as IEnumerable;
break;
default:
break;
}
if (enumerable != null)
{
// check to see if there is at least one item in the Enumerable
return enumerable.GetEnumerator().MoveNext();
}
else
{
// if the list is null, we defer the decision to NullValueHandling
return true;
}
};
}
return property;
}
}
您可以在您的框架的定制契约解析器中实现这个功能,此方案无需修改的你的代码,此方法相当于一些助手方法。
方案二:
如果您可以修改您的类,您可以添加封装方法并为所有空集合设置 NULL。它需要更改类,但它具有更好的性能。可能是您的另一种选择,代码如下:
private List<JcLwtVM> lwtpChildren;
[Newtonsoft.Json.JsonProperty(NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public List<JcLwtVM> lwtChildren
{
get { return lwtpChildren; }
set { lwtpChildren = value == null || value.Count <= 0 ? null : value; }
}
最终我采用上面的方案二,修改我得VM实体类属性代码,目前在应用中没有出现问题。
其次,System.Text.Json:
测试试图弄清楚如何序列化为json对象,并跳过序列化值为空列表的属性。测试没有使用Newtonsoft json。
封装有一个带有属性的对象:
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("hlfj")] public List<YjjcHlfjVM> HlfjList { get; set; }
在我测试中尝试使用以下命令序列化此对象时:
var optionsJson = new JsonSerializerOptions
{
WriteIndented = true,
IgnoreNullValues = true,
PropertyNameCaseInsensitive = true,
};
var json = JsonSerializer.Serialize(HlfjList, optionsJson);
结果中仍然给我一个空数组:"HlfjList": [],难道没有方法或属性阻止它序列化这些空列表吗?我不希望看到HlfjList
集合,因为前端也不希望看到,所以空集合根本不应该出现在json数据里。我需要怎么做呢?
经过一番比对查找代码后发现JsonIgnoreCondition.WhenWritingNull这个属性,于是修改代码再次尝试:
1.添加具有相同签名的新属性,但使用JsonPropertyNameAttribute标记它,以确保使用正确的名称对其进行序列化,并使用JsonIgnoreAttribute进行序列化,以便在返回null时不会对其进行序列化。
2.用JsonIgnore标记的原始属性是无条件的,这样它就永远不会被序列化
3.当实际属性包含空列表时,这个伪属性将返回null(因此被忽略),否则它将返回(non-empty)列表
4.写入虚拟属性只是写入实际属性
代码如下:
[JsonIgnore]
public List<YjjcHlfjVM> HlfjList { get; set; } = new();
[JsonPropertyName("HlfjList")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public List<YjjcHlfjVM> HlfjListExtensions
{
get => HlfjList?.Count > 0 ? HlfjList : null;
set => HlfjList = value ?? new();
}
至此,测试结束,希望对有用到的小伙伴们有帮助,如果您有更好的方案请留言给我。