System.Text.Json 中是否有 Jraw 的等效项

Jar*_*rru 10 c# json.net system.text.json asp.net-core-3.1

我正在将 ASP.NET Core 2 应用程序迁移到 ASP.NET Core 3。我的控制器需要返回具有已经是 JSON 字符串的属性的对象,因此它看起来像这样:

public class Thing {
    public int Id { get; set; }
    public string Name { get; set; }
    public string Data { get; set; } // JSON Data
}

var thing = new Thing
{
    Id = 1,
    Name = "Thing",
    Data = "{\"key\":\"value\"}"
};
Run Code Online (Sandbox Code Playgroud)

Thing应序列化,以便该Data属性不是字符串,而是 JSON 对象的一部分。像这样:

{
    "id": 1,
    "name": "Thing",
    "data": {
        "key": "value"
    }
}
Run Code Online (Sandbox Code Playgroud)

在 .NET Core 2 中,Newtonsoft.Json我使用 的JRaw类型Data,因此序列化器知道该属性已经序列化为 JSON,并且不会尝试将其表示为字符串。

.NET Core 3 使用System.Text.Json,这与JRaw. 有没有等效的东西可以做同样的事情?我能够用作 的JsonElement类型Data并使用 转换字符串JsonDocument.Parse(jsonString).RootElement。这会产生所需的结果,但我想避免不必要的反序列化+序列化步骤,因为数据对象可能相对较大。

dbc*_*dbc 15

.NET 6 引入了Utf8JsonWriter.WriteRawValue(string json, bool skipInputValidation = false)

将输入写入 JSON 内容。预计输入内容是单个完整的 JSON 值。...

写入不受信任的 JSON 值时,请勿设置skipInputValidationtrue,因为这可能会导致写入无效的 JSON,或将无效的整体有效负载写入写入器实例。

因此,您现在可以引入以下转换器:

/// <summary>
/// Serializes the contents of a string value as raw JSON.  The string is validated as being an RFC 8259-compliant JSON payload
/// </summary>
public class RawJsonConverter : JsonConverter<string>
{
    public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        using var doc = JsonDocument.ParseValue(ref reader);
        return doc.RootElement.GetRawText();
    }

    protected virtual bool SkipInputValidation => false;

    public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) =>
        // skipInputValidation : true will improve performance, but only do this if you are certain the value represents well-formed JSON!
        writer.WriteRawValue(value, skipInputValidation : SkipInputValidation);
}

/// <summary>
/// Serializes the contents of a string value as raw JSON.  The string is NOT validated as being an RFC 8259-compliant JSON payload
/// </summary>
public class UnsafeRawJsonConverter : RawJsonConverter
{
    protected override bool SkipInputValidation => true;
}
Run Code Online (Sandbox Code Playgroud)

并将您选择的转换器应用到您的数据模型:

public class Thing {
    public int Id { get; set; }
    public string Name { get; set; }
    [JsonConverter(typeof(UnsafeRawJsonConverter))]
    public string Data { get; set; } // JSON Data
}
Run Code Online (Sandbox Code Playgroud)

笔记:

  • Utf8JsonReader似乎没有等效的方法来读取任何类型的原始值,因此JsonDocument仍然需要反序列化原始 JSON 值。

  • Utf8JsonWriter.WriteRawValue(null)Utf8JsonWriter.WriteRawValue("null")生成相同的 JSON,即null. 反序列化时,doc.RootElement.GetRawText()似乎两者都返回 null 值,而不是包含 token 的字符串null

  • 您似乎关心性能,所以我应用UnsafeRawJsonConverter到您的数据模型。但是,只有在确定Data包含格式正确的 JSON 时才应使用此转换器。如果没有,请使用RawJsonConverter

     [JsonConverter(typeof(RawJsonConverter))]
     public string Data { get; set; } // JSON Data
    
    Run Code Online (Sandbox Code Playgroud)
  • 在 .NET 5 及更早版本中WriteRawValue()不存在,因此您必须将传入的字符串解析为 aJsonDocument并写入:

     public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
     {
         using var doc = JsonDocument.Parse(value);
         doc.WriteTo(writer);
     }
    
    Run Code Online (Sandbox Code Playgroud)

    这当然会检查格式value是否良好;在早期版本中无法编写原始 JSON 并跳过输入验证。

演示小提琴在这里