在.Net Core 3.0中嘗試新的System.Text.Json API
.NET Core 3.0提供了一個名為System.Text.Json的全新名稱空間,它支援reader/writer,文件物件模型(DOM)和序列化程式。在此部落格文章中,我將介紹它如何工作以及如何使用。
官方文件
獲取JSON庫
- 如果以.NET Core為目標,請安裝.NET Core 3.0及以上版本,該版本提供了新的JSON庫和ASP.NET Core整合。
- 如果以.NET Standard或.NET Framework為目標。安裝System.Text.Json NuGet軟體包(確保安裝.NET Framework4.6.0或更高版本)。為了與ASP.NET Core整合,必須以.NET Core 3.0為目標。
NET Core 3.0中JSON特性
新的JSON API通過使用Span進行效能優化,並且可以直接處理UTF-8,而無需轉碼為UTF-16 string 例項。這兩個方面對於ASP.NET Core都是至關重要的,在ASP.NET Core中,吞吐量是關鍵要求。使用System.Text.Json,可以將速度提高大約1.3倍至5倍。
使用System.Text.Json
using System.Text.Json;
using System.Text.Json.Serialization;
使用序列化器Serializer
- 學習.Net Core最好的方式是檢視原始碼,下面是JsonSerializer Serialize的部分原始碼:
namespace System.Text.Json { public static partial class JsonSerializer { /// <summary> /// Convert the provided value into a <see cref="System.String"/>. /// </summary> /// <returns>A <see cref="System.String"/> representation of the value.</returns> /// <param name="value">The value to convert.</param> /// <param name="options">Options to control the conversion behavior.</param> /// <remarks>Using a <see cref="System.String"/> is not as efficient as using UTF-8 /// encoding since the implementation internally uses UTF-8. See also <see cref="SerializeToUtf8Bytes"/> /// and <see cref="SerializeAsync"/>. /// </remarks> public static string Serialize<TValue>(TValue value, JsonSerializerOptions options = null) { return ToStringInternal(value, typeof(TValue), options); } /// <summary> /// Convert the provided value into a <see cref="System.String"/>. /// </summary> /// <returns>A <see cref="System.String"/> representation of the value.</returns> /// <param name="value">The value to convert.</param> /// <param name="inputType">The type of the <paramref name="value"/> to convert.</param> /// <param name="options">Options to control the conversion behavior.</param> /// <remarks>Using a <see cref="System.String"/> is not as efficient as using UTF-8 /// encoding since the implementation internally uses UTF-8. See also <see cref="SerializeToUtf8Bytes"/> /// and <see cref="SerializeAsync"/>. /// </remarks> public static string Serialize(object value, Type inputType, JsonSerializerOptions options = null) { VerifyValueAndType(value, inputType); return ToStringInternal(value, inputType, options); } private static string ToStringInternal(object value, Type inputType, JsonSerializerOptions options) { return WriteCoreString(value, inputType, options); } } }
可以看到序列化最終呼叫的是ToStringInternal這個方法。
- 示例
class Sample
{
public DateTimeOffset Date { get; set; }
public string Summary { get; set; }
}
string Serialize(Sample value)
{
return JsonSerializer.Serialize<Sample>(value);
}
//obj
string SerializeObj(object value)
{
return JsonSerializer.Serialize(value);
}
JsonSerializerOptions用於在序列化時設定配置, 例如處理註釋,null處理,尾隨逗號和命名策略。
public static string ToJson(this object obj)
{
var options = new JsonSerializerOptions() { IgnoreNullValues = true, WriteIndented = true, AllowTrailingCommas = true };
return JsonSerializer.Serialize(obj, options);
}
使用反序列化器Deserialize
Sample Deserialize(string json)
{
var options = new JsonSerializerOptions
{
AllowTrailingCommas = true
};
return JsonSerializer.Deserialize<Sample>(json, options);
}
自定義屬性來控制序列化行為
可以使用自定義屬性來控制序列化行為,例如,忽略屬性或者指定屬性的名稱:
class Sample
{
//忽略
[JsonIgnore]
public DateTimeOffset Date { get; set; }
//指定名稱
[JsonPropertyName("test")]
public string Summary { get; set; }
}
使用DOM
有時,不想反序列化JSON但仍然希望對其內容進行結構化訪問,這時可以使用JsonDocument
var options = new JsonDocumentOptions
{
AllowTrailingCommas = true
};
using (JsonDocument document = JsonDocument.Parse(json, options))
{
//todo
foreach (JsonElement element in document.RootElement.EnumerateArray())
{
DateTimeOffset date = element.GetProperty("date").GetDateTimeOffset();
//todo
}
}
使用Utf8JsonWriter
var options = new JsonWriterOptions
{
Indented = true
};
using (var stream = new MemoryStream())
{
using (var writer = new Utf8JsonWriter(stream, options))
{
writer.WriteStartObject();
writer.WriteString("date", DateTimeOffset.UtcNow);
writer.WriteEndObject();
}
string json = Encoding.UTF8.GetString(stream.ToArray());
Console.WriteLine(json);
}
使用Utf8JsonReader
byte[] data = Encoding.UTF8.GetBytes(json);
Utf8JsonReader reader = new Utf8JsonReader(data, isFinalBlock: true, state: default);
while (reader.Read())
{
Console.Write(reader.TokenType);
switch (reader.TokenType)
{
case JsonTokenType.PropertyName:
case JsonTokenType.String:
{
string text = reader.GetString();
Console.Write(" ");
Console.Write(text);
break;
}
case JsonTokenType.Number:
{
int value = reader.GetInt32();
Console.Write(" ");
Console.Write(value);
break;
}
}
Console.WriteLine();
}
System.Text.Json中的DateTime和DateTimeOffset支援
The System.Text.Json library parses and writes DateTime and DateTimeOffset values according to the ISO 8601:-2019 extended profile. Converters provide custom support for serializing and deserializing with JsonSerializer. Custom support can also be implemented when using Utf8JsonReader and Utf8JsonWriter.
具體請參考官方文件。
示例:
public class DateTimeConverterUsingDateTimeParse : JsonConverter<DateTime>
{
/// <summary>
/// 日期格式
/// </summary>
public string dateTimeFormat { get; }
/// <summary>
/// ctor
/// </summary>
/// <param name="dateTimeFormat"></param>
public DateTimeConverterUsingDateTimeParse(string dateTimeFormat)
{
this.dateTimeFormat = dateTimeFormat;
}
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
Debug.Assert(typeToConvert == typeof(DateTime));
return DateTime.Parse(reader.GetString());
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString(dateTimeFormat));
}
}
public static class JsonHelper
{
/// <summary>Converts to json.</summary>
/// <param name="obj">The object.</param>
/// <param name="dateTimeFormat">The date time format.</param>
/// <returns>System.String.</returns>
public static string ToJson(this object obj, string dateTimeFormat = "yyyy-MM-dd")
{
var options = new JsonSerializerOptions() { IgnoreNullValues = true, WriteIndented = true };
options.Converters.Add(new DateTimeConverterUsingDateTimeParse(dateTimeFormat));
return JsonSerializer.Serialize(obj, options);
}
}
總結
- 在.NET Core 3.0中,System.Text.Json API提供對JSON的內建支援,包括reader/writer,只讀DOM和序列化器/反序列化器。
- 主要目標是實現高效能和低記憶體分配。
- ASP.NET Core 3.0包括對System.Text.Json的支援,預設情況下啟用。