在 System.Text.Json 中是否有 JRaw 的等效物?

9

我正在将一个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\"}"
};

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

{
    "id": 1,
    "name": "Thing",
    "data": {
        "key": "value"
    }
}

在.NET Core 2和Newtonsoft.Json中,我使用了JRaw作为Data类型,因此序列化程序知道该属性已经序列化为JSON并不会尝试将其表示为字符串。
.NET Core 3使用不兼容JRawSystem.Text.Json。是否有相应的等效物来完成同样的事情?我可以使用JsonElement作为Data的类型,并使用JsonDocument.Parse(jsonString).RootElement转换字符串。这将产生所需的结果,但我想避免不必要的反序列化+序列化步骤,因为数据对象可能相对较大。

你仍然可以在 System.Text.Json 无法胜任的情况下使用 Json.Net。System.Text.Json 故意减少了功能,旨在消除对 Json.Net 的依赖 - 但你完全可以将其重新添加进来。 - phuzi
另外,别忘了在用完JsonDocument后进行处理。如果你需要在文档被处理后保存JsonElement,那么你需要将其克隆。 - dbc
1
我应该把它作为答案吗? - dbc
1
@dbc 好的,看来我现在还得继续使用那个好用的 Newtonsoft。 - Jarru
1个回答

14

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

将输入内容作为JSON内容写入。预期输入内容为单个完整的JSON值。...

在编写不受信任的JSON值时,请不要将skipInputValidation设置为true,因为这可能会导致编写无效的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;
}

然后将您选择的转换器应用于您的数据模型:

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

注:

  • Utf8JsonReader does not appear to have an equivalent method to read a raw value of any type, so JsonDocument is still required to deserialize a raw JSON value.

  • Utf8JsonWriter.WriteRawValue(null) and Utf8JsonWriter.WriteRawValue("null") generate identical JSON, namely null. When deserialized, doc.RootElement.GetRawText() seems to return a null value for both, rather than a string containing the token null.

  • You seem to be concerned about performance, so I applied UnsafeRawJsonConverter to your data model. However, you should only use this converter if you are certain that Data contains well-formed JSON. If not, use RawJsonConverter:

     [JsonConverter(typeof(RawJsonConverter))]
     public string Data { get; set; } // JSON Data
    
  • In .NET 5 and earlier WriteRawValue() does not exist, so you will have to parse the incoming string to a JsonDocument and write that:

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

    This of course checks that value is well-formed; there is no ability to write raw JSON and skip input validation in earlier releases.

在这里查看 IT 技术演示 链接


你知道是否有类似于 .net5 的等效物吗?或者有什么解决方法吗? - R.L
@R.L - 我相信在.NET 5中,您必须将原始JSON加载到JsonDocument中,并执行JsonDocument.WriteTo(Utf8JsonWriter) - dbc
@R.L - 或者你可以尝试编写代码,手动从Utf8JsonReader流式传输到Utf8JsonWriter,就像mtoshParsing a JSON file with .NET core 3.0/System.text.Json中所示的那样,但这似乎非常复杂。 - dbc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接