.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信息。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM