当前位置 博文首页 > .NET Core 处理 WebAPI JSON 返回烦人的null为空

    .NET Core 处理 WebAPI JSON 返回烦人的null为空

    作者:Crazy Struggle 时间:2021-01-12 12:02

    前言

          项目开发中不管是前台还是后台都会遇到烦人的null,数据库表中字段允许空值,则代码实体类中对应的字段类型为可空类型Nullable<>,如int?,DateTime?,null值字段序列化返回的值都为null,前台对应字段赋值需要做null值判断,怎么才能全局把null替换为空。

          本文分享WebAPI接口服务统一返回null替换为空的方法。

    一、分析问题

          .NET Core中使用Newtonsoft.Json进行序列化,WebAPI接口返回格式通过Startup.cs类全局设置。想是否可以通过配置把null替换为空值?于是找到了Newtonsoft.Json在序列化和反序列化期间如何处理空值和默认值的属性,具体配置代码如下:

     1 public void ConfigureServices(IServiceCollection services)
     2 {
     3     //配置Mvc + json 序列化
     4     services.AddMvc()
     5         .AddNewtonsoftJson(options =>
     6         {
     7             //数据格式首字母小写 不使用驼峰   小驼峰firstName  大驼峰 FirstName
     8             options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
     9             //使用默认方式,不更改元数据的key的大小写
    10             //options.SerializerSettings.ContractResolver = new DefaultContractResolver();
    11             // 忽略循环引用
    12             options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
    13             // 设置时间格式
    14             options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
    15             //忽略空值 不包含属性的null序列化
    16             //options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
    17             //忽略默认值和null  1、不包含属性默认值和null
    18             //options.SerializerSettings.DefaultValueHandling = DefaultValueHandling.Igno
    19         })
    20 }

     1、空值的处理

          序列化和反序列化时需要忽略值为null的属性,设置SerializerSettings.NullValueHandling的值

    •  NullValueHandling.Ignore 序列化和反序列化对象时忽略空值。
    •  NullValueHandling.Include 序列化和反序列化对象时包含空值。

    2、默认值的处理

          序列化和反序列化时需要忽略默认值属性,设置SerializerSettings.DefaultValueHandling的值

    • DefaultValueHandling.Ignore 序列化和反序列化时忽略默认值
    • DefaultValueHandling.Include序列化和反序列化时包含默认值

    3、示例代码

     1 /*包含属性的默认值与null序列化*/
     2 {
     3   "Name": null,
     4   "Age": 0,
     5   "Partner": null,
     6   "Salary": 0.0
     7 }
     8 /*不包含属性的默认值序列化*/
     9 {
    10   "Name": "Hello World",
    11   "Age": 28
    12 }
    13 /*不包含属性的null序列化*/
    14 {
    15   "Name": "Hello World",
    16   "Age": 28,
    17   "Salary": 0.0
    18 }

    通过上面的分析:一种是不包含属性的默认值序列化,另一种是不包含属性的null序列化,都不能满足目前的需求接口统一返回的null序列化为空。

    二、解决问题

    1、项目WebAPI默认返回的JSON结果格式如下:

     1 {
     2   "code": 0,
     3   "msg": "查询成功",
     4   "data": {
     5     "id": 1,
     6     "title": "炎炎夏日暖暖肚",
     7     "describe": "",
     8     "author": null,
     9     "authorId": null,
    10     "linkSource": null,
    11     "author_Picture": null,
    12     "content": "炎炎夏日,很多人喜欢吃些寒凉的食物解暑,可这种做法非常伤身。",
    13   }
    14 }

    2、需要解决的问题把所有的null替换为空,具体如下图所示:

            

    3、解决方案

          需要自己写一个NullToEmptyStringResolver类,然后重写CamelCasePropertyNamesContractResolver,但是该方法只能解决string类型null→""的问题,对其他可空类型无效,比如:int?、DateTime?等。

     1 public class NullToEmptyStringResolver : CamelCasePropertyNamesContractResolver
     2 {
     3     /// <summary>
     4     /// 创建属性
     5     /// </summary>
     6     /// <param name="type">类型</param>
     7     /// <param name="memberSerialization">序列化成员</param>
     8     /// <returns></returns>
     9     protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    10     {
    11         return type.GetProperties().Select(c =>
    12                 {
    13                     var jsonProperty = base.CreateProperty(c, memberSerialization);
    14                     jsonProperty.ValueProvider = new NullToEmptyStringValueProvider(c);
    15                     return jsonProperty;
    16                 }).ToList();
    17     }
    18 }
    19 
    20 public class NullToEmptyStringValueProvider : IValueProvider
    21 {
    22     private readonly PropertyInfo _memberInfo;
    23     /// <summary>
    24     /// 构造函数
    25     /// </summary>
    26     /// <param name="memberInfo"></param>
    27     public NullToEmptyStringValueProvider(PropertyInfo memberInfo)
    28     {
    29         _memberInfo = memberInfo;
    30     }
    31 
    32     /// <summary>
    33     /// 获取Value
    34     /// </summary>
    35     /// <param name="target"></param>
    36     /// <returns></returns>
    37     public object GetValue(object target)
    38     {
    39         var result = _memberInfo.GetValue(target);
    40         if (_memberInfo.PropertyType == typeof(string) && result == null)
    41             result = string.Empty;
    42         return result;
    43     }
    44 
    45     /// <summary>
    46     /// 设置Value
    47     /// </summary>
    48     /// <param name="target"></param>
    49     /// <param name="value"></param>
    50     public void SetValue(object target, object value)
    51     {
    52         _memberInfo.SetValue(target, value);
    53     }
    54 }

          在Startup.cs代码里面修改,标记为红色的代码,如下所示:

     1 //配置MVC+JSON序列化
     2 services
     3     .AddMvc(options =>{options.EnableEndpointRouting = false;})
     4     .AddNewtonsoftJson(options =>
     5     {
     6         //使用默认方式,不更改元数据的key的大小写
     7         //options.SerializerSettings.ContractResolver = new DefaultContractResolver();
     8         //数据格式首字母小写 不使用驼峰   小驼峰firstName  大驼峰 FirstName
     9         //options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    10         options.SerializerSettings.ContractResolver = new NullToEmptyStringResolver();
    11         // 忽略循环引用
    12         options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
    13         // 设置时间格式
    14         options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
    15         //忽略空值 不包含属性的null序列化
    16         //options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
    17         //忽略默认值和null  1、不包含属性默认值和null 
    18         //options.SerializerSettings.DefaultValueHandling = DefaultValueHandling.Igno
    19     })

          修改完配置,重新运行完成,实现null替换为空的效果,运行结果如下所示:

     1 {
     2   "code": 0,
     3   "msg": "查询成功!",
     4   "data": {
     5     "id": 1,
     6     "title": "炎炎夏日暖暖肚",
     7     "describe": "",
     8     "author": "",
     9     "authorId": "",
    10     "linkSource": "",
    11