System.Text.Json 自定義 Conveter

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

反序列化時會發生錯誤,異常如下:

System.Text.Json 自定義 Conveter

所以還需要自定義一個 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(node。ToJsonString(),

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(newJsonString);

WriteLine(model == newModel);

node[

“Name”

] =

345

WriteLine(JsonSerializer。Deserialize(node。ToJsonString(),

new

JsonSerializerOptions

{

Converters =

{

new

StringOrIntConverter()

}

})?。Name);

輸出結果如下:

System.Text.Json 自定義 Conveter

output

More

可能你會問為什麼不直接用

object

,如果使用

object

的話,上面的

Equals

判斷就要改寫了,需要自己重新實現比較邏輯,而用

string

就不需要了 希望上面自定義 Converter 的程式碼對你有所幫助~

02

經典回顧

System.Text.Json 自定義 Conveter