gpt4 book ai didi

c# - 如何在.net core 3.1中使用System.Text.Json获取对象内部对象的值

转载 作者:行者123 更新时间:2023-12-03 23:12:00 29 4
gpt4 key购买 nike

创建了一个 .Net 核心 3.1 Web 应用程序和已发布的请求,其中 Requested 模型看起来像,

public class RequestPayload
{
public string MessageName { get; set; }

public object Payload { get; set; }
}

我对核心 3.1 非常陌生,正在努力获得 Payload 属性的值(value),谁能帮我解决这个问题?

在寻找解决方案的同时,我还比较了 牛顿软件 System.Text.Json 并得到 错误 .

使用 牛顿软件我是 能够序列化和反序列化如下所示的模型,
public class RequestPayload
{
public string MessageName { get; set; }

public object Payload { get; set; }

//Problem is here -> TYPE
public Type PayloadType { get; set; }
}

但使用 System.Text.Json 我是 不是
虽然 序列化 得到错误“System.Text.Json.JsonException:'检测到不支持的可能的对象循环。”

测试 反序列化 ,以某种方式创建了 JSON 并尝试使用 System.Text.Json 反序列化它,但收到错误“System.Text.Json.JsonException:'JSON 值无法转换为 System.Type。”

二手 System.Text.Json.JsonSerializer ,这是一个问题还是有其他可能使这个工作?

最佳答案

I am very new to core 3.1 and struggling to get the value of Payload property, Can anyone help me on this?



对于 System.Object属性, 不像 Newtonsoft.Json , System.Text.Json是否 不是 尝试推断 type原始值的 JSON 负载(例如 true12345.67"hello" )。类似地,对于像对象和数组这样的复杂 JSON 值(例如 {"Name":"hi"}[1, 2, 3]),对象属性设置为装箱的 JsonElement表示传入的 JSON。这类似于 Newtonsoft.Json店家 JObjectobject property对于复杂类型。
https://docs.microsoft.com/en-us/dotnet/api/system.text.json.jsonelement?view=netcore-3.1

就像你如何使用 Newtonsoft.Json 的 JObject ,您可以使用 JsonElement 遍历和访问 JSON 文档对象模型 (DOM) 中的值。并在其上调用转换 API 以获取 .NET 值(例如 GetProperty(String)GetInt32())。

以下示例显示了如何访问 Payload值,一旦您将 JSON 反序列化为 RequestPayload .
private static void ObjectPropertyExample()
{
using JsonDocument doc = JsonDocument.Parse("{\"Name\":\"Darshana\"}");
JsonElement payload = doc.RootElement.Clone();

var requestPayload = new RequestPayload
{
MessageName = "message",
Payload = payload
};

string json = JsonSerializer.Serialize(requestPayload);
Console.WriteLine(json);
// {"MessageName":"message","Payload":{"Name":"Darshana"}}

RequestPayload roundtrip = JsonSerializer.Deserialize<RequestPayload>(json);

JsonElement element = (JsonElement)roundtrip.Payload;
string name = element.GetProperty("Name").GetString();
Assert.Equal("Darshana", name);
}

While finding the solution I also compared Newtonsoft and System.Text.Json and got Error.



即使序列化包含 System.Type 的类属性(property)还行,是 不是 推荐,尤其是对于 Web 应用程序(尽管存在信息泄露的潜在问题)。

另一方面, 反序列化 JSON 转换为包含 Type 的类属性,尤其是使用 Type.GetType(untrusted-string-input)绝对不推荐因为它在您的应用程序中引入了潜在的安全漏洞。

这就是为什么内置 System.Text.Json有意 不支持序列化/反序列化 Type特性。您在序列化时看到的异常消息是因为 Type在其对象图中包含一个循环和 JsonSerializer目前不处理周期。如果您只关心将类序列化(即写入)为 JSON,您可以创建自己的 JsonConverter<Type>添加对它的支持(生成与 Newtonsoft.Json 相同的 JSON)。类似以下内容将起作用:
private class CustomJsonConverterForType : JsonConverter<Type>
{
public override Type Read(ref Utf8JsonReader reader, Type typeToConvert,
JsonSerializerOptions options)
{
// Caution: Deserialization of type instances like this
// is not recommended and should be avoided
// since it can lead to potential security issues.

// If you really want this supported (for instance if the JSON input is trusted):
// string assemblyQualifiedName = reader.GetString();
// return Type.GetType(assemblyQualifiedName);
throw new NotSupportedException();
}

public override void Write(Utf8JsonWriter writer, Type value,
JsonSerializerOptions options)
{
// Use this with caution, since you are disclosing type information.
writer.WriteStringValue(value.AssemblyQualifiedName);
}
}

然后,您可以将自定义转换器添加到选项中并将其传递给 JsonSerializer.Serialize :
var options = new JsonSerializerOptions();
options.Converters.Add(new CustomJsonConverterForType());

考虑 重新评估为什么您需要 Type正在序列化和反序列化的类上的属性。

https://github.com/dotnet/corefx/issues/42712有关为什么不应该反序列化包含 Type 的类的更多信息和上下文使用 Type.GetType(string) 的属性.

以下是有关如何编写自定义转换器的更多信息:
https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to

一种可以更安全地工作的方法(因此 我会推荐 )是使用类型鉴别器枚举,其中包含您期望和支持的静态已知类型的列表,并基于枚举显式创建这些类型 JsonConverter<Type> 内的值.

下面是一个示例:
// Let's assume these are the list of types we expect for the `Type` property
public class ExpectedType1 { }
public class ExpectedType2 { }
public class ExpectedType3 { }

public class CustomJsonConverterForType : JsonConverter<Type>
{
public override Type Read(ref Utf8JsonReader reader, Type typeToConvert,
JsonSerializerOptions options)
{
TypeDiscriminator typeDiscriminator = (TypeDiscriminator)reader.GetInt32();

Type type = typeDiscriminator switch
{
TypeDiscriminator.ExpectedType1 => typeof(ExpectedType1),
TypeDiscriminator.ExpectedType2 => typeof(ExpectedType2),
TypeDiscriminator.ExpectedType3 => typeof(ExpectedType3),
_ => throw new NotSupportedException(),
};
return type;
}

public override void Write(Utf8JsonWriter writer, Type value,
JsonSerializerOptions options)
{
if (value == typeof(ExpectedType1))
{
writer.WriteNumberValue((int)TypeDiscriminator.ExpectedType1);
}
else if (value == typeof(ExpectedType2))
{
writer.WriteNumberValue((int)TypeDiscriminator.ExpectedType2);
}
else if (value == typeof(ExpectedType3))
{
writer.WriteNumberValue((int)TypeDiscriminator.ExpectedType3);
}
else
{
throw new NotSupportedException();
}
}

// Used to map supported types to an integer and vice versa.
private enum TypeDiscriminator
{
ExpectedType1 = 1,
ExpectedType2 = 2,
ExpectedType3 = 3,
}
}

private static void TypeConverterExample()
{
var requestPayload = new RequestPayload
{
MessageName = "message",
Payload = "payload",
PayloadType = typeof(ExpectedType1)
};

var options = new JsonSerializerOptions()
{
Converters = { new CustomJsonConverterForType() }
};

string json = JsonSerializer.Serialize(requestPayload, options);
Console.WriteLine(json);
// {"MessageName":"message","Payload":"payload","PayloadType":1}

RequestPayload roundtrip = JsonSerializer.Deserialize<RequestPayload>(json, options);
Assert.Equal(typeof(ExpectedType1), roundtrip.PayloadType);
}

关于c# - 如何在.net core 3.1中使用System.Text.Json获取对象内部对象的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59799836/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com