Dar*_*ana 3 c# json.net .net-core-3.1 system.text.json
创建了一个.Net Core 3.1 Web 应用程序并发布了请求,其中 Requested 模型看起来像,
public class RequestPayload
{
public string MessageName { get; set; }
public object Payload { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我对核心 3.1 非常陌生,正在努力获得 Payload 属性的价值,有人可以帮我吗?
在找到解决方案的同时,我还比较了Newtonsoft和System.Text.Json并得到了Error。
使用Newtonsoft我能够序列化和反序列化如下所示的模型,
public class RequestPayload
{
public string MessageName { get; set; }
public object Payload { get; set; }
//Problem is here -> TYPE
public Type PayloadType { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
但是使用System.Text.Json我不是 在序列化时出现错误“System.Text.Json.JsonException:'检测到不支持的可能的对象循环。”
为了测试反序列化,以某种方式创建了 JSON 并尝试使用 System.Text.Json 对其进行反序列化,但收到错误“System.Text.Json.JsonException:'JSON 值无法转换为 System.Type。”
使用System.Text.Json.JsonSerializer,这是一个问题还是有其他可能使这个工作?
ahs*_*han 12
我对核心 3.1 非常陌生,正在努力获得 Payload 属性的价值,有人可以帮我吗?
对于System.Object性能,不同于 Newtonsoft.Json,System.Text.Json并没有尝试来推断type的JSON有效载荷为原始值(例如true,12345.67,"hello")。同样,对于复杂的 JSON 值,如对象和数组(例如{"Name":"hi"}或[1, 2, 3]),对象属性设置为JsonElement表示传入 JSON的装箱。这类似于如何Newtonsoft.Json将 a 存储JObject到object property复杂类型中。请参阅https://docs.microsoft.com/en-us/dotnet/api/system.text.json.jsonelement?view=netcore-3.1
就像使用 Newtonsoft.Json 的 一样JObject,您可以使用JsonElement和调用转换 API来遍历和访问 JSON 文档对象模型 (DOM) 中的值以获取 .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);
}
Run Code Online (Sandbox Code Playgroud)
在找到解决方案的同时,我还比较了 Newtonsoft 和 System.Text.Json 并得到了错误。
尽管序列化包含System.Type属性的类是可以的,但不建议这样做,尤其是对于 Web 应用程序(尽管存在信息泄露的潜在问题)。
在另一方面,反序列化JSON成一个包含类Type物业,尤其是在使用Type.GetType(untrusted-string-input)时绝对不推荐,因为它在应用程序中引入了潜在的安全漏洞。
这就是为什么内置函数System.Text.Json故意不支持序列化/反序列化Type属性。您在序列化时看到的异常消息是因为Type在其对象图中包含一个循环,并且当前JsonSerializer不处理循环。如果您只关心将类序列化(即写入)到 JSON,您可以创建自己的类JsonConverter<Type>来添加对它的支持(生成相同的 JSON Newtonsoft.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);
}
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以将自定义转换器添加到选项中并将其传递给JsonSerializer.Serialize:
var options = new JsonSerializerOptions();
options.Converters.Add(new CustomJsonConverterForType());
Run Code Online (Sandbox Code Playgroud)
考虑重新评估为什么您需要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);
}
Run Code Online (Sandbox Code Playgroud)