
在微軟官方網站上檢視.NET 8新功能時,看到一句話:「.NET 8 中的 System.Text.Json 序列化和還原序列化功能進行許多改進。」當下腦袋充滿了各種問號,因為當時的我對Json的認知都還停留在Newtonsoft.Json這套件上,後來上網查了一下才知道:微軟早在.NET Core 3.0開始就內建 System.Text.Json 做為預設Json處理核心,也是為了擺脫對Json.Net的依賴。
記得早期有一段時期,.NET Framework 4點多的時候,曾經因為發佈出來的程式版本與config中指定的Newtonsoft.Json版本不合而去更新Newtonsoft.Json組件、或追加調整config指定版本;現在回想起來,如果這部分可以直接採用內建套件、就不會再擔心發生版本差異的問題了。
發展至今,System.Text.Json是否可以完整取代Newtonsoft.Json我不知道,但我針對性的以公司內常用的Json功能進行檢查:幾乎可以說是換掉namespace命名空間即可;而少部分有差異的地方才需要調整程式碼。
在此先補充說明:此篇文章僅針對公司內常用功能進行檢查,不做效能判斷,一來是公司內較少需要大量且頻繁地進行Json資料轉換,其次兩種套件的效能比較早在.NET Core 3.0的版本時就有,僅附網址提供參考:https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-apis/?WT.mc_id=DOP-MVP-37580
開發程式中約有八到九成使用Json的部分都是序列化、和反序列化,這部分只要改參考即可:
using System.Text.Json;
var jsonString = "{\"Name\":\"Small Small Fish\",\"Age\":20, \"Sex\":1, \"SexText\":\"Female\" , \"Desc\":\"non-marine fish\" }";
Console.WriteLine(jsonString);
var student = JsonSerializer.Deserialize<Student>(jsonString);
var text = JsonSerializer.Serialize(student);
預設的序列化和反序列化功能有以下兩點特徵:
- Enum屬性預設是轉int
- 不會自動縮排
在使用Serialize的過程中,最常注意的就是縮排,預設沒有自動縮排這一點對我來說是比較好,因為比較節省空間、尤其是寫Log的時候,但對有的人來說並不友善,因為有了縮排才好檢視。
在這方面,System.Text.Json與Newtonsoft.Json不同,使用的物件屬性名稱有一點差異、需要微調程式碼。
Newtonsoft.Json是使用JsonSerializerSettings、其屬性是Formatting為enum:
var setting = new JsonSerializerSettings
{
Formatting = Newtonsoft.Json.Formatting.None
};
JsonConvert.SerializeObject(value, setting);
System.Text.Json則是使用JsonSerializerOptions、其屬性是WriteIndented為bool:
var options = new JsonSerializerOptions
{
WriteIndented = true
};
var text2 = JsonSerializer.Serialize(student, options);
除此之外,常見且比較有可能用到的諸如:enum屬性不是轉為int而是轉為string的話、或是屬性名稱有所差異等,都可以依靠追加attribute來支援的功能:
public enum StudentSex
{
Male = 0,
Female = 1
}
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
public StudentSex Sex { get; set; }
[JsonConverter(typeof(JsonStringEnumConverter))]
public StudentSex SexText { get; set; }
public int No { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string Tag { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public string Address1 { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
public string Address2 { get; set; }
[JsonPropertyName("Desc")]
public string Description { get; set; }
}
如此一來,同樣是enum,但Sex為數值、SexText則為文字;且程式中Description的屬性在Json字串內則是Desc。
var jsonString = "{\"Name\":\"Small Small Fish\",\"Age\":20, \"Sex\":1, \"SexText\":\"Female\", \"Address2\": \"test\", \"Tag\": null, \"No\": 0, \"Desc\":\"non-marine fish\" }";
var student = JsonSerializer.Deserialize<Student>(jsonString);
var text1 = JsonSerializer.Serialize(student, JsonSerializerOptions.Default);
Console.WriteLine("serialize by default:");
Console.WriteLine(text1);
Console.WriteLine();
var options = new JsonSerializerOptions
{
ReadCommentHandling = JsonCommentHandling.Skip,
WriteIndented = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
};
var text2 = JsonSerializer.Serialize(student, options);
Console.WriteLine("serialize by options:");
Console.WriteLine(text2);
程式執行結果:

其中,Ignore忽略轉換功能比較特殊,可透過attribute指定特定屬性支援、也可以直接透過序列化設定進行指定,而且除了null以外也可以指定default值就進行忽略(例如int的default值為0),或是Always一直忽略轉換該屬性、Never一直不能忽略該屬性。
雖然System.Text.Json我是在Net8推出之後才開始接觸,但文中上述程式碼卻並非都是.NET 8才可以使用,至少.NET 6運作無誤。
Reference: