System.Text.Json 中 JObject 的等效项 [英] Equivalent of JObject in System.Text.Json

查看:31
本文介绍了System.Text.Json 中 JObject 的等效项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 DTO 类,它具有 JObject 类型的属性.此 DTO 类在多个服务之间通过 HTTP 发送/接收.使用 JObject 是因为 ExtractedData 没有预定义的属性

I have DTO class that has a property of type JObject. This DTO class is send/receive over HTTP between multiple services. JObject is used because the ExtractedData does not have predefined properties

public class MyDTO
{
    public JObject ExtractedData {get;set;}
}

我正在将此项目转换为 .NET 5.什么与 .NET 5 中的 JObject 等效?我试图避免 JsonDocument 因为(来自 文档):

I am converting this project to .NET 5. What is equivalent to JObject in .NET 5? I am trying to avoid JsonDocument because (from the docs):

JsonDocument 将数据的内存视图构建到一个池中缓冲.因此,与 Newtonsoft.Json 中的 JObject 或 JArray 不同,JsonDocument 类型实现了 IDisposable 并且需要在一个内部使用使用块.

JsonDocument builds an in-memory view of the data into a pooled buffer. Therefore, unlike JObject or JArray from Newtonsoft.Json, the JsonDocument type implements IDisposable and needs to be used inside a using block.

我打算使用 JsonElement.这是最合适的选择还是有任何其他类型可用于将 JSON 作为对象保存?

I am planing to use JsonElement. Is this the most appropriate choice or is there any other type available to hold JSON as an object?

推荐答案

最接近于 JObject 确实是 JsonElement 这样你就可以修改你的 DTO 如下:

The closest equivalent to JObject is indeed JsonElement so you could modify your DTO as follows:

public class MyDTO
{
    public JsonElement ExtractedData {get;set;}
}

无需担心在内部将任何文档处理为 JsonElementConverter.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializer" rel="noreferrer">JsonSerializer 返回一个非池化元素(通过克隆元素在 .NET 5 中).

There is no need to worry about disposing of any documents as, internally, the JsonElementConverter used by JsonSerializer returns a non-pooled element (by cloning the element in .NET 5).

但是,对应关系并不准确,因此请记住以下几点:

However, the correspondence is not exact, so keep the following in mind:

  1. JsonElement 代表任何 JSON 值,因此最接近于 JToken 不是 JObject.由于 JsonElement 是一个 struct,因此没有对应于 JSON 对象的子类.如果要将 ExtractedData 限制为 JSON 对象,则需要在 setter 中检查:

  1. JsonElement represents any JSON value and thus corresponds most closely to JToken not JObject. As JsonElement is a struct there is no subclass corresponding to a JSON object. If you want to constrain ExtractedData to be a JSON object you will need to check this in the setter:

public class MyDTO
{
    JsonElement extractedData;

    public JsonElement ExtractedData
    {
        get => extractedData;
        set
        {
            if (value.ValueKind != JsonValueKind.Object
                // && value.ValueKind != JsonValueKind.Null Uncomment if you want to allow null
                )
                throw new ArgumentException(string.Format("{0} is not a JSON object type", value.ValueKind));
            extractedData = value;
        }
    }
}

  • 由于JsonElement 是一个结构体,所以默认值不是null.那么,它是什么?结果证明 default(JsonElement)ValueKind = JsonValueKind.Undefined:

  • Since JsonElement is a struct, the default value is not null. So, what is it? It turns out that default(JsonElement) has ValueKind = JsonValueKind.Undefined:

    没有值(与 Null 不同).

    There is no value (as distinct from Null).

    如果您尝试使用 JsonSerializer 序列化此类默认 JsonElement,则会引发异常.IE.如果你只是这样做

    If you attempt to serialize such a default JsonElement with JsonSerializer, an exception will be thrown. I.e. if you simply do

    var json = JsonSerializer.Serialize(new MyDTO());
    

    然后一个 System.InvalidOperationException: Operation is not valid due to the current state of the object. 异常被抛出.

    Then a System.InvalidOperationException: Operation is not valid due to the current state of the object. exception is thrown.

    您有几个选择可以避免这个问题:

    You have a few options to avoid this problem:

    public class MyDTO
    {
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
        public JsonElement ExtractedData {get;set;}
    }
    

    这会导致在序列化期间跳过 ExtractedData 的未初始化值.

    This causes uninitialized values of ExtractedData to be skipped during serialization.

    在 .NET Core 3.x 中 JsonIgnoreCondition 不存在,因此您可以将 ExtractedData 定义为可以为空:

    In .NET Core 3.x JsonIgnoreCondition does not exist, so you could instead define ExtractedData to be nullable:

    public class MyDTO
    {
        public JsonElement? ExtractedData {get;set;}
    }
    

    或者您可以像这样将其初始化为空 JsonElement:

    Or you could initialize it to a null JsonElement like so:

    public class MyDTO
    {
        public JsonElement ExtractedData {get;set;} = JsonExtensions.Null;
    }
    
    public static class JsonExtensions
    {
        static readonly JsonElement nullElement = CreateNull();
    
        public static JsonElement Null => nullElement;
    
        static JsonElement CreateNull()
        {
            using var doc = JsonDocument.Parse("null");
            return doc.RootElement.Clone();
        }
    }
    

    这两个选项都会导致 ExtractedData 的未初始化值序列化为 null.

    Both options cause uninitialized values of ExtractedData to serialize as null.

    另见相关问题:

    这篇关于System.Text.Json 中 JObject 的等效项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆