.net5 core webapi进阶之一:System.Text.Json的用法详解(上篇)JSON的读写

从本篇开始写 .net5 core webapi 进阶系列,先从JSON这种数据格式开始,原因如下:

1 . 够简洁;

2 . 易于理解;

3 . 其格式和面向对象的语言天然匹配;

4 . 多语言(Javascript 、C# 、Java 等)支持;

毫无疑问,JSON是不同语言,不同系统之间进行数据交换的最好选择,没有之一,

如果XML代表着上一个10年,那么JSON将统治下一个10年,也许更久。。。

 

一 、System.Text.Json 的内部结构。

System.Text.Json.dll 程序集中有两个名称空间,分别是 System.Text.Json 和 System.Text.Json.Serialization

用反编译工具打开System.Text.Json并只显示公有类型和成员,得到如下的类/结构:

System.Text.Json用于读写JSON,

System.Text.Json.Serialization用于JSON的序列化和反序列化。

 

二 、新建一个.net5 core webapi 项目演示System.Text.Json的用法。

项目名称为webapidemo2,按照惯例,

删除根目录下的 WeatherForecast.cs 文件和Controllers目录下的 WeatherForecastController.cs 文件,

新建一个API控制器(不是MVC控制器)文件 JsonDemoController.cs,如下:

在此文件中引用如下几个名称空间:

using System.Buffers;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
using static System.Text.Json.JsonElement;

在项目根目录下新建一个Models的文件夹,

然后添加一个 Company.cs 和 User.cs 的类文件作为序列化和反序列化使用 ,如下:

 Company.cs 和 User.cs 的代码先不写,在演示序列化和反序列化的时候再补充完成。

 

我们在 JsonDemoController.cs 这个控制器中编写7个终结点,分别完成如下7个功能:

1 . 终结点 JsonDemo1();作用:return 一个最简单的 JSON 字符串;

{"userid":123, "username":"jacky"}

2 . 终结点: JsonDemo2();作用:return 一个带字符串数组的 JSON 字符串

{"userid":123, "username":"jacky", "mobile":["13244445555","18966667777"]}

3 . 终结点: JsonDemo3();作用:return 一个带对象数组的 JSON 字符串

{"userid":123, "username":"jacky", "employees":[{"userid":834,"username":"simon"},{"userid":835,"username":"roger"}]}

4 . 终结点: JsonDemo4();作用:用 JsonDocument 类解析一个JSON文件,读取指定属性的值

文件位于根目录下,名称叫 appcom.json,格式如下:

{
  "CompanyName": "top",
  "Website": "www.xxxx.com",
  "Address": "开曼群岛",
  "Boss": {"userid": 1001, "username": "王五", "mobile": "13300047775"},
  "Employees": [
    {
      "userid": 2113,
      "username": "张三",
      "mobile": "13378465709"
    },
    {
      "userid": 3266,
      "username": "李四",
      "mobile": "13378465709"
    }
  ],
  "PhoneNumber": ["010-93847485","15890276458"]
}

5 . 终结点:JsonDemo5();作用:用 Utf8JsonReader 遍历 JSON 文件(文件同 4.)

6 . 终结点:JsonDemo6();作用:将 Company 和 User 实例序列化成 JSON 对象

7 . 终结点:JsonDemo7();作用:将 JSON 对象反序列化成 Company 和 User 实例

 

三 、编码,7个终结点的代码如下。

1 . 终结点: JsonDemo1();

        [Route("json1")]
        [HttpGet]
        public string Demo1()
        {
            //{"userid":123, "username":"jacky"}

            //表示基于堆、使用字节数组存储数据的输出接收器,可向其中写入数据。
            ArrayBufferWriter<byte> buffer = new ArrayBufferWriter<byte>();

            //utf8编码的JSON写入器,可以将int,string,array等数据写入到JSON中
            Utf8JsonWriter writer = new Utf8JsonWriter(buffer); 
            writer.WriteStartObject(); //表示一个开头花括号 "{"

            //写入属性及其值,这两行语句可以换成 writer.WriteNumber("userid", 123);
            writer.WritePropertyName("userid");
            writer.WriteNumberValue(123);

            writer.WriteString("username", "jacky");
            writer.WriteEndObject(); //表示一个结尾花括号 "}"
            writer.Flush();//写入到buffer

            //ReadOnlySpan表示的存储区有更好的性能和内存开销
            ReadOnlySpan<byte> span = buffer.WrittenSpan;            
            string strJson = Encoding.UTF8.GetString(span);

            return strJson;  
        }

打开POSTMAN ,用GET方式访问网址:http://localhost:61946/api/jsondemo/json1 得到如下结果:

 

 2 . 终结点: JsonDemo2();

        [Route("json2")]
        [HttpGet]
        public string Demo2()
        {
            //{"userid":123, "username":"jacky", "mobile":["13244445555","18966667777"]}

            ArrayBufferWriter<byte> buffer = new ArrayBufferWriter<byte>();
            Utf8JsonWriter writer = new Utf8JsonWriter(buffer);
            writer.WriteStartObject();
            writer.WriteNumber("userid", 123);
            writer.WriteString("username", "jacky");

            //写入json数组开始,这两行语句可以换成 writer.WriteStartArray("mobile");
            writer.WritePropertyName("mobile");
            writer.WriteStartArray();//写入json数组开始,表示一个开头中括号[

            writer.WriteStringValue("13244445555");//简单的值对象输出用对应的Value结尾的方法
            writer.WriteStringValue("18966667777");
            writer.WriteEndArray();//写入json数组结束,表示一个结束中括号]
             
            writer.WriteEndObject();
            writer.Flush();

            ReadOnlySpan<byte> span = buffer.WrittenSpan;
            string strJson = Encoding.UTF8.GetString(span);

            return strJson;
        }

打开POSTMAN ,用GET方式访问网址:http://localhost:61946/api/jsondemo/json2 得到如下结果:

 

3 . 终结点: JsonDemo3();

        [Route("json3")]
        [HttpGet]
        public string Demo3()
        {
            //{"userid":123, "username":"jacky", "employees":[{"userid":834,"username":"simon"},{"userid":835,"username":"roger"}]}
            //mock一个泛型List<User>供下面使用
            List<User> userList = new List<User>();
            userList.Add(new User { UserId = 834, UserName = "simon" });
            userList.Add(new User { UserId = 835, UserName = "roger" });
             
            ArrayBufferWriter<byte> buffer = new ArrayBufferWriter<byte>();
            Utf8JsonWriter writer = new Utf8JsonWriter(buffer);
            writer.WriteStartObject();
            writer.WriteNumber("userid", 123);
            writer.WriteString("username", "jacky");

            writer.WriteStartArray("employees");
            foreach (User user in userList) //遍历写入User对象
            {
                writer.WriteStartObject();
                writer.WriteNumber("userid", user.UserId);
                writer.WriteString("username", user.UserName);
                writer.WriteEndObject();
            }
            writer.WriteEndArray();

            writer.WriteEndObject();
            writer.Flush();

            ReadOnlySpan<byte> span = buffer.WrittenSpan;
            string strJson = Encoding.UTF8.GetString(span);

            return strJson;
        }

打开POSTMAN ,用GET方式访问网址:http://localhost:61946/api/jsondemo/json3 得到如下结果:

 

4 . 终结点: JsonDemo4();

        [Route("json4")]
        [HttpGet]
        public string Demo4()
        {
            StringBuilder sb = new StringBuilder();

            string filePath = Path.GetFullPath("./appcom.json");
            using (FileStream stream = System.IO.File.OpenRead(filePath))
            {
                JsonDocument doc = JsonDocument.Parse(stream);
                JsonElement root = doc.RootElement;

                //得到单个属性的值
                string addr = root.GetProperty("Address").GetString();
                sb.Append("公司地址 :  " + addr + Environment.NewLine);


                //属性的值是数组时取值
                ArrayEnumerator arr = root.GetProperty("PhoneNumber").EnumerateArray();
                sb.Append("联系电话 :  ");
                foreach (JsonElement ele in arr)
                {
                    sb.Append(ele.GetString() + ",");
                }
                sb.Append(Environment.NewLine);


                //属性的值是对象时取值
                sb.Append("老板名字 :  ");
                ObjectEnumerator arr2 = root.GetProperty("Boss").EnumerateObject();
                while (arr2.MoveNext())
                {
                    if (arr2.Current.Name == "username")
                    {
                        sb.Append(arr2.Current.Value.GetString() + ",");
                    }
                }
                sb.Append(Environment.NewLine);


                //属性的值是对象数组时取值
                sb.Append("员工名单 :  ");
                ArrayEnumerator arr3 = root.GetProperty("Employees").EnumerateArray();
                foreach (JsonElement ele in arr3)
                {
                    sb.Append(ele.GetProperty("username").GetString() + ",");
                }

            }
            return sb.ToString();
        }

打开POSTMAN ,用GET方式访问网址:http://localhost:61946/api/jsondemo/json4 得到如下结果:

 

5 . 终结点: JsonDemo5();

        [Route("json5")]
        [HttpGet]
        public string Demo5()
        {
            string filePath = Path.GetFullPath("./appcom.json");
            ClearFileBom(filePath);//去除文件中的BOM头,避免解析错误

            byte[] contents = System.IO.File.ReadAllBytes(filePath);
            JsonReaderOptions options = new JsonReaderOptions
            {
                AllowTrailingCommas = true, //忽略属性末尾多余的逗号
                CommentHandling = JsonCommentHandling.Skip //跳过注释
            };


            //变量span也可用构造方法new ReadOnlySpan<byte>(contents);初始化
            ReadOnlySpan<byte> span = contents.AsSpan<byte>();
            Utf8JsonReader reader = new Utf8JsonReader(span, options);

            StringBuilder sb = new StringBuilder();
            while (reader.Read()) //遍历所有属性
            {
                sb.Append("depth:" + reader.CurrentDepth + "---"); //当前属性深度
                sb.Append("JsonTokenType:" + reader.TokenType.ToString()); //属性token类型
                sb.Append("------【" + Encoding.UTF8.GetString(reader.ValueSpan) + ""); //属性名称
                switch (reader.TokenType)
                {
                    case JsonTokenType.String:
                        sb.Append(" --- value is=" + reader.GetString()); //不同的属性值类型用不同的GetXxx()取值
                        break;
                    case JsonTokenType.Number:
                        sb.Append(" --- value is=" + reader.GetInt32());
                        break;
                }
                sb.Append(Environment.NewLine); 
            }

            return sb.ToString();
        }

        private void ClearFileBom(string filePath)
        {
            //以UTF-8编码读取带BOM头文件的内容
            Encoding end = new UTF8Encoding(true);
            string str = string.Empty;
            using (StreamReader reader = new StreamReader(filePath, end))
            {
                str = reader.ReadToEnd();
            }
            //以UTF-8编码重新写入不带BOM头文件的内容
            end = new UTF8Encoding(false);
            using (StreamWriter writer = new StreamWriter(filePath, false, end))
            {
                writer.Write(str);
            }
        }

 打开POSTMAN ,用GET方式访问网址:http://localhost:61946/api/jsondemo/json5 得到如下结果:

 

 可以看到按顺序输出了整个JSON信息。

 

posted @ 2021-02-21 18:47  屏风马  阅读(3165)  评论(0编辑  收藏  举报