问题描述
我有一个 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 因为(来自 docs):
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 并且需要在一个使用块.
我打算使用 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:
JsonElement
代表任何 JSON 值,因此最接近于JToken
不是JObject
.由于JsonElement
是一个struct
,因此没有对应于 JSON 对象的子类.如果要将ExtractedData
限制为 JSON 对象,则需要在 setter 中检查:
JsonElement
represents any JSON value and thus corresponds most closely toJToken
notJObject
. AsJsonElement
is astruct
there is no subclass corresponding to a JSON object. If you want to constrainExtractedData
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 不同).
如果您尝试使用 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:
在 .NET 5 中,您可以应用
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
像这样:
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
.
另见相关问题:
- 将 newtonsoft 代码转换为 .net core 中的 System.Text.Json 3. 相当于 JObject.Parse 和 JsonProperty.
- 由于对象 (System.Text.Json) 的当前状态,操作无效.
这篇关于System.Text.Json 中 JObject 的等效项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!