【问题标题】:Is there an equivalent for JRaw in System.Text.JsonSystem.Text.Json 中是否有 JRaw 的等价物
【发布时间】:2020-07-10 21:35:45
【问题描述】:

我正在将 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 使用System.Text.Json,与JRaw 不兼容。有没有做同样事情的等价物?我能够使用JsonElement 作为Data 的类型并使用JsonDocument.Parse(jsonString).RootElement 转换字符串。这会产生预期的结果,但我想避免不必要的反序列化+序列化步骤,因为数据对象可能相对较大。

【问题讨论】:

  • 您仍然可以在 System.Text.Json 无法使用的时候使用 Json.Net。 System.Text.Json 有意简化功能,并被引入以消除对 Json.Net 的依赖 - 但没有理由不能将其重新添加。
  • 另外,完成后不要忘记处理JsonDocument。如果你需要一个JsonElement在文件被处理后仍然存在,你需要克隆它。
  • 我应该这样回答吗?
  • @dbc 继续。看来我现在必须继续使用旧的 Newtonsoft。

标签: c# json.net asp.net-core-3.1 system.text.json


【解决方案1】:

.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 似乎没有等效的方法来读取任何类型的原始值,因此仍需要JsonDocument 来反序列化原始 JSON 值。

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

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

     [JsonConverter(typeof(RawJsonConverter))]
     public string Data { get; set; } // JSON Data
    

演示小提琴here.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-02
    • 2011-07-29
    • 2013-06-21
    • 2014-01-09
    • 2012-02-18
    相关资源
    最近更新 更多