.NET Core 3.0 里新的JSON API

来源:https://www.cnblogs.com/cgzl/archive/2019/10/25/11736011.html
-Advertisement-
Play Games

為什麼需要新的JSON API? 為什麼需要新的JSON API? JSON.NET 大家都用過,老版本的ASP.NET Core也依賴於JSON.NET。 JSON.NET 大家都用過,老版本的ASP.NET Core也依賴於JSON.NET。 然而這個依賴就會引起一些版本問題:例如ASP.NET ...


為什麼需要新的JSON API 

JSON.NET 大家都用過,老版本的ASP.NET Core也依賴於JSON.NET 

然而這個依賴就會引起一些版本問題:例如ASP.NET Core某個版本需要使用JSON.NET v10,而另一個庫需要使用JSON.NET v11;或者JSON.NET 出現了一個新版本,而ASP.NET Core還不能支持這個版本,而您卻想使用該版本。 

 

System.Text.Json 

隨著NET Core 3.0的出現,出現了System.Text.Json命名空間和它下麵一些用於處理JSON的類。 

 

特點

這個內置JSON API具有與生俱來的高性能、低分配的特點: 

JSON.NET 使用.NET 裡面的字元串作為基本數據類型,其實也就是UTF16,而.NET Core中新的JSON API直接使用數據原始的UTF8格式。 

新的JSON API基於Span<byte>這個數據類型來進行操作JSON數據,從而具有低分配的特點,這就可以極大的改善吞吐量和記憶體使用情況。 

 

但是新的JSON API的特性還不那麼豐富,有一些JSON.NET具有的特性都還不支持。 

 

例子 

隨便找了一個JSON示例文件: 

"post Title": "Programming" , 
"language": 
"author": 
"firstName": "Nick", 
"lastName": "Carter" 
"publishedAt 
"wordCount " : 
13435, 
"isoriginal"• 
true, 
"tags" • 
• "C#", "JSON API", ".NET Core" ]

 

針對這個文件,需要修改一下它的屬性: 

sample.json File P 「 operties 
Advanced 
Custom T00 一 Namespace 
Custom T00- 
Copy to Output 「 to 
Build Action 
〔 を

 

Utf8JsonReader 

先使用 Utf8JsonReader 來讀取JSON文件。 

Utf8JsonReader 並不會讀取文件或者stream,它會讀取Span數據類型。 

 

直接上代碼: 

static void Elgin(stringC] 
gx•gs 
File . ReadAllBytes( path: "sample.json" ); 
var dataBytes 
dataBytes .AsSpan( ) ; 
var jsonSpan 
new Utf8JsonReader(jsonSpan); 
var jsonReader = 
while (jsonReader.Read()) 
Console . jsonReader)); 
I reference 
private static string GetTokenInfo(Utf8JsonReader jsonReader) 
jsonReader . TokenType switch 
JsonTokenType.StartObject 
"START OBJECT" , 
JsonTokenType 
. EndObject "END OBJECT" , 
JsonTokenType.StartArray 
"START ARRAY" , 
JsonTokenType. EndArray "End ARRAY" , 
JsonTokenType. PropertyName $ " PROPERTY: {jsonReader.GetString()}" , 
$"COMMENT: {jsonReader.GetString()}" , 
JsonTokenType 
. Comment 
JsonTokenType.String $"STRING: {jsonReader.GetString()}" , 
$"NUMBER: {jsonReader.GetInt32()}" , 
JsonTokenType.Number 
$"BOOL: {jsonReader.GetBoolean()}" , 
JsonTokenType 
. True 
$"BOOL: {jsonReader.GetBoolean()}" , 
JsonTokenType 
JsonTokenType.Null 
"NULL" , 
$ TOKEN: {jsonReader.TokenType}"

Main方法裡面,我們使用File.ReadAllBytessample.json文件讀取數格式為byte[],然後通過AsSpan這個擴展方法將其轉化為Span<byte>數據類型,然後把它傳遞到 Utf8JsonReader 的構造函數來創建一個JSON的reader 

 

接下來使用while迴圈對JSON數據的每個Token進行讀取,每次執行Read()方法時,reader就會移動到JSON數據裡面的下一個Token那裡。 

 

Token分成幾種類型,GetTokenInfo方法就是判斷一下Token的類型,並返回一些描述性信息,這裡面應該是包含了所有的類型。這裡面使用到了C# 8  switch 表達式。 

 

運行程式 

結果如下: 

hema Selected> 
"post Title": "Programming" , 
"language": 
"author": 
"lastName": "Carter" 
"firstName": 
"publishedAt 
"Nick", 
"wordCount " : 
13435, 
"isoriginal"• 
true, 
"tags" • 
• "C#", "JSON 
API", ".NET Core" 
PROPERTY: postTit1e 
STRING: Programming 
PROPERTY: language 
STRING: 
PROPERTY: author 
START OBJECT 
PROPERTY: firstName 
STRING: Nick 
PROPERTY: lastName 
STRING: carter 
END OBJECT 
PROPERTY: publishedAt 
STRING: 
PROPERTY: wordcount 
NUMBER: 13435 
PROPERTY: isoriginal 
BOOL: True 
PROPERTY: tags 
START ARRAY 
STRING: 
STRING: JSON API 
STRING: .NET core 
End ARRAY 
END OBJECT

可以看到sample.json文件裡面的每個Token都被正確的顯示了。 

 

JsonDocument 

JsonDocument是基於Utf8JsonReader 構建的JsonDocument 可分析 JSON 數據並生成只讀文檔對象模型 (DOM),可對模型進行查詢,以支持隨機訪問和枚舉。使用 JsonDocument 分析常規 JSON 有效負載並訪問其所有成員比使用 Json.NET  2-3 倍,且為合理大小(即 < 1 MB)的數據所分配的量非常少。 

JsonDocument可以處理Span,也可以處理Stream 

 

例子: 

using 
using 
var 
var 
File .0penRead( path: 
"sample.json"); 
stream = 
JsonDocument . Parse( stream) ; 
doc

這裡我通過File.OpenReadjson文件轉化為stream。然後使用JsonDocument.Parse方法把stream解析成JSON文檔對象模型。 

註意,這裡我使用了C# 8using var語法,這個以後再說。 

 

下麵我們開始從這個JSON文檔對象模型的根節點開始遍歷,也就是RootElement 

root 
var 
doc . Root Element;

 

然後通過root這個JsonElement類型的對象的GetProperty方法來獲得相應的屬性,而且這個方法可以連串使用: 

firstName 
var 
root .GetProperty( "author") 
. GetProperty( "firstName" ) 
. GetString( ) ;

最後一行使用GetString方法來獲得該屬性的字元串值。 

 

然後我們可以寫一個遞歸調用的方法來遍歷整個模型的每個屬性: 

EnumerateElement(JsonElement root) 
private static void 
foreach (var prop in root. EnumerateObject()) 
if (prop.Value.ValueKind = 
JsonValueKind .0bject) 
Console . WriteLine($" {prop . Name}" ) ; 
Console.WriteLine(" 
- Object Start - 
EnumerateElement(prop . Value); 
Console.WriteLine(" 
Object End 
else 
{prop. Value.GetRawText()}");

這個方法接受JsonElement類型的對象,然後對該元素的屬性進行迴圈。 

如果當前屬性是另一個對象,那麼就繼續遞歸調用這個方法; 

否則就輸出原始的文本。 

 

最後調用該方法: 

File. OpenRead( 
"sample.json"); 
using var stream 
path: 
JsonDocument . Parse( stream) ; 
using var doc - 
doc . Root Element; 
var root 
var firstName 
root .GetProperty( "author") 
. GetProperty( "firstName" ) 
. GetString( ) 
Console.WriteLine($"First Name is {firstName}"); 
EnumerateElement(root);

 

輸出結果為: 

First Name 
post Title: 
language: 
author 
is Nick 
" Programmi ng" 
Object Start 
irstName: "Nick" 
lastName: "Carter" 
Object End 
publishedAt : 
22T2ø: 21 . eeøz" 
rdcount: 13435 
isoriginal: true 
ags: [ "C#", " 
JSON API 
% ".NET core" :

與json文件的內容匹配。 

 

Utf8JsonWriter 

下麵研究一下如何寫入json文件。這裡需要使用Utf8JsonWriter類。 

直接看代碼: 

這個類需要傳遞的參數類型是Stream或者Buffer,也就是向StreamBuffer裡面寫入數據。 

 

那麼就提供一個buffer 

var buffer = 
new 
= new Utf8JsonWriter(buffer); 
using var 
'son

 

下麵單獨寫一個方法,來生成json數據: 

PopulateJson(Utf8JsonWriter json) 
private static void 
Json. 
write 
W rite 
W r ite Base64St ringVaIue 
W r ite Boolean 
W r ite BooleanVaIue 
W r iteCo m mentVaIue 
Write EndArray 
W r ite EndObject 
Wr iteNuII 
W r ite NullVaIue 
Write Number 
W rite Nu mbe rVaIue 
void 
void 
void 
void 
void 
void 
void 
void 
void 
void 
void 
(JsonEncodedText propertyName, ReadOnIyS 
Writes the pre-encoded property name and 
a name/value pair of a JSON object. 
utf8PropertyName, Re; 
propertyName, ReadO 
(string propertyName,

參數類型是Utf8JsonWriter。通過智能提示可以看到它提供了很多用於寫入不同類型數據的方法。 

 

JSON對象 

現在我想寫一個json對象,那麼就從WriteStartObject()開始,然後以WriteEndObject()結束: 

json . WriteStartObject( ); 
json.WriteEndObject();

這樣的話,實際上我已經擁有了一個合法的json文檔。 

 

寫屬性和值 

可以分開寫屬性和值: 

json . WritePropertyName( "title"); 
json . WriteStringValue( " Programming" ) ;

 

也可以同時把屬性和值寫出來: 

json .WriteString( propertyName: "language" , 
"C#"); 
value:

 

顯示JSON數據 

我先寫這些內容,然後在Main方法裡面調用一下: 

grgs) 
static void Mgin(stringC] 
new ArrayBufferWriter<byte>(); 
var buffer - 
new Utf8JsonWriter(buffer); 
using var Ison = 
PopulateJson( j son) ; 
I reference 
private static void PopulateJson(Utf8JsonWriter json) 
Json. 
Json. 
Json. 
Json. 
Json. 
Json. 
Json. 
WriteStartObject( ) ; 
WritePropertyName( "title"); 
WriteStringValue( " Programming" ) ; 
WriteString( propertyName: "language" , 
WriteString( propertyName: "firstName" , 
WriteString( propertyName: "lastName" , 
WriteEndObject( ) ; 
"C#"); 
value: 
"Nick"); 
value: 
"Carter"); 
value:

 

首先需要告訴writer把它的內容flush給buffer,使用這個buffer我們可以獲得writer的輸出,這樣的話就會得到一個byte數組,然後把這個byte數組轉化為字元串,這樣就可以在控制台顯示它了: 

new ArrayBufferWriter<byte>(); 
var buffer = 
new Utf8JsonWriter(buffer); 
using var Ison = 
PopulateJson( json); 
json. Flush(); 
var output = buffer.WrittenSpan.ToArray(); 
Encoding. UTF8. GetString(output); 
var outJson - 
Console. WriteLine(outJson);

 

運行一下看看效果: 

{"title" : "Programming" , "language" : "C#" , "firstName" : "Nick" , "lastName" : "Carter"}

沒啥太大的問題,就是格式不好看。 

 

對輸出進行格式化 

.NET Core提供了一個JsonWriterOptions類,它可以對Writer進行一些設置。 

var options = 
Indented = 
new JsonWriterOptions 
true 
new Utf8JsonWriter(buffer, 
using var Ison = 
options);

這裡對輸出進行了縮進,最後把這個options傳遞給Utf8JsonWriter的構造函數即可。 

 

再次運行: 

"title": "Programming", 
"language" • " 
"firstName": "Nick", 
"lastName" : "Carter"

現在好看多了。 

 

JsonSerializer 

前面幾節的內容可能稍微有點底層,我們大部分時候可能只需要對C#的類進行串列化或者將JSON數據反串列化成C#類,在.NET Core 3.0裡面,我們可以使用JsonSerializer這個類來做這些事情。 

 

例子:

還是使用之前用到的json數據: 

"post Title": "Programming" 
"language": 
"author": 
"firstName": "Nick", 
"lastName": "Carter" 
"publishedAt 
"wordCount " : 
13435, 
"isoriginal"• 
true, 
"tags" • 
"JSON API", ".NET Core"

 

然後我們需要建建立兩個類,對應這個文件: 

public class 
BlogPost 
O references 
public 
O references 
public 
O references 
public 
O references 
public 
O references 
public 
O references 
public 
public 
I reference 
{ get; set; } 
string 
Post Title 
{ get; set; } 
string 
Language 
{ get; set; } 
Author Author 
{ get; set; 
DateTime PublishedAt 
{ get; set; } 
int 
WordCount 
{ get; set; } 
bool 
Isoriginal 
:iag$ 
{ get; set; } 
stringC] 
public class Author 
O references 
{ get; set; } 
public string 
FirstName 
O references 
{ get; set; } 
public string 
LastName

 

反串列化 

可以使用JsonSerializer類的Deserialize()方法對json數據反串列化。這個方法支持三種類型的輸入參數,分別是: 

  • JSON數據的字元串 

  • Utf8JsonReader 

  • ReadOnlySpan<byte>,它裡面包含JSON數據 

 

為了簡單一點,我直接把json文件讀取成字元串,然後傳給Deserialize方法: 

var text = 
var post = 
File. ReadAllText( path: 
"sample. json"); 
JsonSerializer . text); 
Console . WriteLine(post. PostTitle); 
Console . WriteLine($" {post .Author . FirstName} 
{post .Author . LastName}"); 
Console . WriteLine( post. PublishedAt);

然後我試圖列印出反串列化之後的一些屬性數據。但是這不會成功。因為JSON文件裡面數據的大小寫命名規範使用的是camel casing(簡單理解為首字母是小寫的),而預設情況下Deserializer會尋找Pascal casing這種規範(簡單理解為每個單詞的首字母都是大寫的)的屬性名。 

 

格式化 

為解決這個問題,就需要使用JsonSerializerOptions類: 

var 
var 
options = 
new JsonSeria1izerOptions 
PropertyNamingPolicy = 
JsonNamingPolicy . CamelCase 
post = 
JsonSerializer.Deserialize<BlogPost>(text, options);

建立該類的一個實例,設置PropertyNamingPolicyCamelCase,然後把這個實例傳遞給Deserialize方法的第二個參數。 

 

運行看結果: 

Programmi ng 
Nick - Carter 
18/22/2819 PM

這次就沒有問題了。 

 

串列化 

JsonSerializer也支持串列化,也就是把C#數據轉化為JSON數據: 

這裡使用了相同的options 

 

運行結果: 

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Go語言基礎之數組 本文主要介紹Go語言中數組(array)及它的基本使用。 Array ( 數組 ) 數組是同一種數據類型元素的集合。 在Go語言中,數組從聲明時就確定,使用時可以修改數組成員,但是數組大小不可變化。 基本語法: 數組定義: 比如: , 數組的長度必須是常量,並且長度是數組類型的一 ...
  • [TOC]   c++是一種中級語言,是c的擴充,是一種面向對象的程式設計語言,可以運行到多個平臺。這裡直接講語法。   基礎c++模板: javascript 函數類型 函數名(參數表);例如: int max(int x,int y,int z); int ...
  • 恢復內容開始 需要安裝三個庫(requests,BeautifulSoup4,lxml) pip install requests BeautifulSoup4 lxml 彈幕消息會滾動在終端上 且會在當前目錄下生成以主播名字命名的文件 恢復內容結束 ...
  • 1 背景 像我們去面試一些大公司的時候,就會遇到一些關於緩存的問題。可能很多同學都是接觸過,多多少少瞭解一些,但是如果沒有好好記錄這些內容,不熟練精通的話,在真正面試的時候,就很難答出來了。 在我們的平常的項目中多多少少都會使用到緩存,因為一些數據我們沒有必要每次查詢的時候都去查詢到資料庫。 特別是 ...
  • 前言 Redis哨兵模式,用現在流行的話可以說就是一個“哨兵機器人”,給“哨兵機器人”進行相應的配置之後,這個"機器人"可以7*24小時工作,它能能夠自動幫助你做一些事情,如監控,提醒,自動處理故障等。 Redis-sentinel簡介 Redis-sentinel是Redis的作者antirez, ...
  • Spring註解之@Conditional 【1】@Conditional介紹 ​ @Conditional是Spring4新提供的註解,它的作用是按照一定的條件進行判斷,滿足條件給容器註冊bean。 ​ @Conditional源碼: ​ 從代碼中可以看到,需要傳入一個Class數組,並且需要繼承 ...
  • 一.open文件讀取 1.open('file','mode')打開一個文件 file 要打開的文件名,需加路徑(除非是在當前目錄) mode 文件打開的模式 需要手動關閉close 2.with open('file','mode')as... 不需要手動關閉文件 3.'r': 以只讀模式打開(默 ...
  • 恢復內容開始 最近各大一二線城市的房租都有上漲,究竟整體上漲到什麼程度呢?我們也不得而知,於是乎筆者為了一探究竟,便用 Python 爬取了房某下的深圳租房數據。以下是本次的樣本數據: 除去【不限】的數據(因為可能會與後面重疊),總數據量為 16971 ,其中後半部分地區數據量偏少,是由於該區房源確 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...