备忘:Json字符串反序列化时,对于Null值的处理
(新手小白,如有写错或者有更高明的写法,烦请大佬指正,谢谢!)
最近在做开放接口时,遇到一个问题,API的部分字段是非必填的,当字段类型为引用类型,且客户对接该API时,因为字段非必填,就不给这个字段或直接给null值时,WebApi底层自动反序列化后,你所拿到的数据中,不给或给的值为null的字段,会等于null;
null值容易在系统中引发异常,例如直接赋值到实体上,插入数据库,而数据库该字段不允许为null,则会引发报错,因此,在对数据库操作前需要将为null的值转换为空字符串;
例如:
模型类:
public class AddressInputModel
{
/// <summary>
/// 收件人姓名
/// </summary>
public string BuyerFullName { get; set; }
/// <summary>
/// 收件人国家
/// </summary>
public string Country { get; set; }
/// <summary>
/// 收件地址省/州
/// </summary>
public string BuyerState { get; set; }
/// <summary>
/// 收件地址城市
/// </summary>
public string BuyerCity { get; set; }
/// <summary>
/// 街道地址1
/// </summary>
public string BuyerStreet1 { get; set; }
/// <summary>
/// 街道地址2
/// </summary>
public string BuyerStreet2 { get; set; }
/// <summary>
/// 地址邮编
/// </summary>
public string BuyerZipCode { get; set; }
/// <summary>
/// 联系电话
/// </summary>
public string BuyerPhone { get; set; }
/// <summary>
/// 收件邮箱
/// </summary>
public string BuyerEmail { get; set; }
}
控制器层接口:
[HttpPost]
public object Create(AddressInputModel input)
{
//参数验证代码&Service方法调用
}
客户给的Json为
{
"BuyerFullName": "Name",
"Country": "TH",
"BuyerState": "A",
"BuyerCity": "B",
"BuyerStreet1": "C",
"BuyerZipCode": "2",
"BuyerPhone": null,
"BuyerEmail": ""
}
那么,input.BuyerStreet2、input.BuyerPhone应该是等于null的
遇到这种问题,其实解决的方式有很多,最简单的就是一个个做判断,例如:
if(string.IsNullOrWhiteSpace(input.BuyerStreet2))
input.BuyerStreet2 = string.Empty;
但是像这种写法,会导致代码冗余难看,毫无复用性
因此我也找度娘查询了一下这种情况的解决方案,可能是所想的关键词不对,一直没有查询到,于是上Newtonsoft.Json查看官方文档,地址:https://www.newtonsoft.com/json
平时用Newtonsoft.Json只用了JsonConvert.SerializeObject、JsonConvert.DeserializeObject最简单的方法,了解别的比较少,在文档浏览中,发现Newtonsoft.Json支持自定义配置反序列化,
//如果 .NET 值在序列化时为空,Json.NET 将跳过写入 JSON 属性,如果在反序列化时 JSON 属性为空,则将跳过设置字段/属性
var setting = new JsonSerializerSettings();
setting.NullValueHandling = NullValueHandling.Ignore;
说明地址:https://www.newtonsoft.com/json/help/html/SerializationSettings.htm
于是自己写了一个公共方法用于处理此类业务场景,直接贴代码
1、首先定义模型的基类,用于赋默认值:
/// <summary>
/// 实体模型基类,为防止新增字段为null值报错
/// </summary>
public abstract class EntityBase
{
/// <summary>
/// 默认时间
/// </summary>
private static readonly DateTime DefaultTime = new DateTime(1900, 1, 1);
protected EntityBase()
{
var props = GetType().GetProperties();
foreach (var prop in props)
{
if (prop.PropertyType == typeof(string))
{
prop.SetValue(this, string.Empty);
}
if (prop.PropertyType == typeof(DateTime))
{
prop.SetValue(this, DefaultTime);
}
if (prop.PropertyType == typeof(decimal))
{
prop.SetValue(this, 0M);
}
}
}
}
2、输入模型类继承基类:
public class AddressInputModel : EntityBase
{
/// <summary>
/// 收件人姓名
/// </summary>
public string BuyerFullName { get; set; }
/// <summary>
/// 收件人国家
/// </summary>
public string Country { get; set; }
/// <summary>
/// 收件地址省/州
/// </summary>
public string BuyerState { get; set; }
/// <summary>
/// 收件地址城市
/// </summary>
public string BuyerCity { get; set; }
/// <summary>
/// 街道地址1
/// </summary>
public string BuyerStreet1 { get; set; }
/// <summary>
/// 街道地址2
/// </summary>
public string BuyerStreet2 { get; set; }
/// <summary>
/// 地址邮编
/// </summary>
public string BuyerZipCode { get; set; }
/// <summary>
/// 联系电话
/// </summary>
public string BuyerPhone { get; set; }
/// <summary>
/// 收件邮箱
/// </summary>
public string BuyerEmail { get; set; }
}
3、定义一个方法用于重新赋值
/// <summary>
/// Json反序列化
/// 默认的Json反序列化会将为null的值赋值到字段
/// 调用此方法,为null的字段将不会赋值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="model"></param>
/// <returns></returns>
public T DeserializeNullValueHandling<T>(T model)
{
var inputStr = JsonConvert.SerializeObject(model);
var setting = new JsonSerializerSettings();
setting.NullValueHandling = NullValueHandling.Ignore;
model = JsonConvert.DeserializeObject<T>(inputStr, setting);
return model;
}
4、方法调用:
[HttpPost]
public object Create(AddressInputModel input)
{
input = DeserializeNullValueHandling(input);
.............
}
问题搞定,且方法复用性强,可以省掉很多代码