System。Text。Json 自定義 Conveter
Intro
System。Text。Json
作為現在 。NET 預設提供的高效能 JSON 序列化器,對於一些比較特殊型別支援的並不太好,業務需求中總是有各種各樣的需要,很多時候就需要用到自定義 Converter ,對於微軟新出的
DateOnly
/
TimeOnly
也是需要自定義 Converter 來支援的
Sample
遇到一個(偽)需求,一個
Id
屬性可能是字串也可能是整型數字,舉個栗子,
{
“Id”
:
1
,
“Name”
:
“Test”
}
{
“Id”
:
“這是一個 Id”
,
“Name”
:
“Test”
}
上面這是兩個 JSON,想實現用同一個 Model 來儲存結果,應該怎麼做呢?
如果
Id
只會是整數或者整數的字串,那麼我們就可以用
int
來表示,
System。Text。Json
從 5。0 開始支援解析帶引號的數字,也就是數字的字串形式可以參考:https://github。com/dotnet/runtime/issues/30255,只需要配置
JsonNumberHandling
, 在 ASP。NET Core 中預設是啟用的,是可以把
“1”
反序列化成一個
int
型別的
但是我們的示例中的
Id
是可能不是數字的,轉成數字可能會失敗的,所以想要把它當作
string
來處理,最後 model 是這樣的
public
record TestModel
{
public
string
Id {
get
; init; } =
default
!;
public
string
? Name {
get
;
set
; }
}
但是如果是上面第一種形式的
JSON
反序列化時會發生錯誤,異常如下:
所以還需要自定義一個 Converter 來支援將數字轉換成一個字串,Converter 實現如下, 屬性型別是什麼,泛型型別就應該是什麼
public
class
StringOrIntConverter
:
JsonConverter
<
string
>
{
public
override
string
Read
(
ref
Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options
)
{
if
(reader。TokenType == JsonTokenType。Number)
{
return
reader。GetInt32()。ToString();
}
return
reader。GetString();
}
public
override
void
Write
(
Utf8JsonWriter writer,
string
value
, JsonSerializerOptions options
)
{
writer。WriteStringValue(
value
);
}
}
使用 Converter 的方式有兩種,一種是在某個屬性上新增
JsonConverter
來使用,另一種是作為全域性 Converter 來使用,直接配置
JsonSerializerOptions
中的 Converter
屬性使用 Converter 示例:
public
record TestModel
{
[
JsonConverter(typeof(StringOrIntConverter))
]
public
string
Id {
get
; init; } =
default
!;
public
string
? Name {
get
;
set
; }
}
配置
JsonSerializerOptions
示例:
JsonSerializer。Deserialize
new
JsonSerializerOptions
{
Converters =
{
new
StringOrIntConverter()
}
});
這樣我們就可以支援從一個
int
到
string
的轉換了,完整示例如下:
var
model =
new
TestModel
{
Id =
“123”
,
Name =
“456”
};
var
jsonString = JsonSerializer。Serialize(model);
WriteLine(jsonString);
var
node = JsonNode。Parse(jsonString);
ArgumentException。ThrowIf(node,
nameof
(node));
node[
“Id”
] =
123
;
var
newJsonString = node。ToJsonString();
WriteLine(newJsonString);
var
newModel = JsonSerializer。Deserialize
WriteLine(model == newModel);
node[
“Name”
] =
345
;
WriteLine(JsonSerializer。Deserialize
new
JsonSerializerOptions
{
Converters =
{
new
StringOrIntConverter()
}
})?。Name);
輸出結果如下:
output
More
可能你會問為什麼不直接用
object
,如果使用
object
的話,上面的
Equals
判斷就要改寫了,需要自己重新實現比較邏輯,而用
string
就不需要了 希望上面自定義 Converter 的程式碼對你有所幫助~
02
—
經典回顧