5

【茶包射手雜記】JObject 無法被 System.Text.Json 序列化

 1 year ago
source link: https://blog.darkthread.net/blog/jobject-in-system-text-json/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

【茶包射手雜記】JObject 無法被 System.Text.Json 序列化-黑暗執行緒

.NET Core 開始內建 System.Text.Json,強調效能快、省記憶體,計劃逐步取代 Json.NET。從 .NET Core 3 一路發展,System.Text.Json 加入 JsonObject、JsonArray 支援 DOM 巡覽及 JSON 文件編修,功能及順手度慢慢追上 Json.NET。但就實務面,Json.NET 有大量現成範例、程式庫滿足五花八門需求,為求統一硬要全面改寫成 System.Text.Json 並非明智之舉。於是,專案混用 System.Text.Json 與 Json.NET 的案例還蠻常見的。

最近遇到一例,ASP.NET Core Minimal API 整合現有程式庫,方法回傳類型為 JObject,我沒想太多,就用 Results.Json() 打算將其轉為 JSON 傳回前端:

using System.Text.Json;
using Newtonsoft.Json.Linq;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => Results.Json(someLegacyApi()));

app.Run();

JObject someLegacyApi() => new JObject
{
    ["cpu"] = "i7",
    ["os"] = new JObject
    {
        ["ver"] = "Windows 11",
        ["lang"] = "en-US",
    },
    ["drives"] = new JArray
    {
        "SSD 1TB", "HDD 2TB"        
    }
};

預期該傳回 {"cpu":"i7","os":{"ver":"Windows 11","lang":"en-US"},"drives":["SSD 1TB","HDD 2TB"]},結果得到 {"cpu":[],"os":[[[]],[[]]],"drives":[[],[]]} 這種鬼東西:

Fig1_638201053861797855.png

我很快明白,JObject 是 Json.NET 特製的類別,無法像一般類別用 Reflection GetProperties() 列舉屬性,Json.NET 是自己加上訂製邏輯才能順利序列化。而要解這個問題不難,先將 JObject 轉成 JSON 字串,再反序列化還原成 System.Text.Json 世界的類別,之後即可暢行無阻。

試了兩種寫法:JsonSerializer.Deserialize<JsonElement>()JsonDocument.Parse(),都能順利解決問題:

app.MapGet("/jsonelem", () => Results.Json(
    JsonSerializer.Deserialize<JsonElement>(someLegacyApi().ToString())));
app.MapGet("/jsondoc", () => Results.Json(
    JsonDocument.Parse(someLegacyApi().ToString())));

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK