添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

备忘: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);
     .............

问题搞定,且方法复用性强,可以省掉很多代码

接收前端Post来的Json对象,一直转换为空,就是Json对象无法成功转换成当前对象 检查我们的模型类数据类型,将其设置为可null,或者全部设置为string,即可。 如果前端给我们的float类型传了一个空字符串,将转换报错,所以导致我们的接口接收对象一直为Null 先看下我们常规声明一个变量的代码: JObject json = null; MessageBox.Show(json==null?"null":"no null"); // 输出:null 对一个变量赋 null 值,我们可以直接通过 ... == null 进行判断,但是当我们按照这样的原则去设置和检查 JObject 中项的属性时确遇到了问题: JObject json = new JObject(){{"age",null}}; MessageBox.Show(json["age"]= WebApi 数据协议组件主要负责处理客户端与服务器之间的数据交换。它包含了序列化与反序列化、数据格式化、模型绑定、验证等多个方面的功能,确保在传输和处理数据时的安全性和一致性。.NET 8 为 WebApi 数据协议组件带来了多项关键改进,这些改进不仅提升了性能,还增强了安全性和灵活性。开发者应充分利用这些新特性,以构建出更具竞争力的 Web 应用程序。希望本文能帮助你更好地理解和运用 .NET 8 中的 WebApi 数据协议组件。 在做数据库规划时,通常会规划一些系统字段,也就是由数据库本身自行指定默认值到这个字段上,创建新的“创建时间(CreateDate)”字段就会常常这样设计。 如果希望能有默认值,且让.net 程序在新增信息到数据库时不用指定的值的话,那么你需要在你的该属性(property)上面加上一个DatabaseGenerated属性(Attribute),并传入DatabbaseG... .Net中使用WebApi参数接受一直是个问题,不同的传参方式后台接受的方式也不一样。之后.Net Core出来后WebApi也发生了变化,在.Net Framework时WebApi是有单独的ApiController的,在.Net Core时没有独立的ApiController了,这样接受参数上也会有一定的区别。传参有两种Get和Post方式,通过使用发现Get方式接受参数主要是Url传递其实还是比较简单的,Post方式就比较特殊了,内容是放在Body中的,因此不同时形式的传递方式接受就不一样了,为此做 在工作停滞了一年以后,重入职场,作为一个即将步入中年程序员,真的感觉大脑像被抽空过一样,重拾那些平台和框架,就像捡起洒落一地的沙子一样费劲。 废话不多说,就说最近接触WEB API,一边写API,一边写客户端程序进行接口测试,接口调通并不难,但被传参问题卡住了,WEB API中POST方法接收的来自客户端的参数始终为空NULL值,查阅了很多人的解决方法,比如request.ContentType = "application/json"; 或比如将API中入参类型改为dynamic,或改为object,或 有时间整理一下并写下来,防止以后再犯同样的错误。 大家可以阅读关于Web API参数绑定的官方文档parameter-binding-in-aspnet-web-api 言归正传,这是我最初的请求,测试时不起作用: $.ajax({ type: "POST", 一、相关概念和简单API的使用1. 什么是ASP.NET-WebAPI?ASP.NET Web API 是一种框架,用于轻松构建可以访问多种客户端(包括浏览器和移动设备)的 HTTP 服务。 ASP.NET Web API 是一种用于在 .NET Framework 上构建 RESTful 应用程序的理想平台。2. 关于RESTful的理解REST是英文representational state... 1. 导言 路由系统是请求消息进入ASP.NET Web API消息处理管道的第一道屏障,其根本目的在于利用注册的路由对请求的URL进行解析以确定目标HTTPController和Action的名称,以及与目标Action方法某个参数进行绑定的路由变量。 WebService和WCF的协议都是soap协议,数据的序列化和反序列化都是soap的格式。而WebAPI是基于Http协议,请求和返回格... 字段拼写错误需要检查下; 看看接收的list对象是否被赋予了set属性 如果还没有接收到试试看用dynamic 类型接收传过来的参数,分析看看否字段传过来了没,然后对比分析正常传值中哪些没传过来,仔细看没传过来的那些数据是什么问题 前端只要给 parentId 的赋值从 “” 调整为 null 之后我们的接口就可以正常运行了,但是有的时候前端的组件这里取值可能是和一些组件库绑定的,不太方便绑定默认值null,很多情况下组件库组件的默认值都是 “” 空字符串的形式,所以经过和前端同事多次沟通之后想着从后端彻底解决这个问题,经过研究之后编写了下面的 NullableConverter 转换器,只要在项目启动的时候注册到 AddJsonOptions 其中即可。我们这里将上级部门ID定义为可以为空的类型,因为有些部门不存在上级部门。