.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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...