使用 NewtonSoft.JSON 序列化接口/抽象对象 [英] Serializing an interface/abstract object using NewtonSoft.JSON

查看:22
本文介绍了使用 NewtonSoft.JSON 序列化接口/抽象对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

反序列化接口和抽象属性的一种方法是在序列化和反序列化期间将 TypeNameHandling 设置为 Auto.但是,当我在直接序列化和反序列化接口对象时尝试相同时,它不起作用 -

interface ISample{字符串键 { 获取;放;}}A类:ISample{公共字符串密钥 { 获取;放;}公共 A(字符串键){this.Key = 键;}}B类:ISample{公共字符串密钥 { 获取;放;}公共 B(字符串键){this.Key = 键;}}

序列化和反序列化代码-

ISample a = new A("keyA");ISample b = new B("keyB");var settings = new JsonSerializerSettings();settings.TypeNameHandling = TypeNameHandling.Auto;var stringA = JsonConvert.SerializeObject(a, settings);var stringB = JsonConvert.SerializeObject(b, settings);Console.WriteLine(stringA);Console.WriteLine(stringB);a = JsonConvert.DeserializeObject(stringA, settings);b = JsonConvert.DeserializeObject(stringB, settings);

我注意到即使在设置 TypeNameHandling.Auto 时,序列化字符串中也不存在类型信息.但是,将 TypeNameHandling 设置为 Object 或 All 有效.

我在这里遗漏了一些基本的东西吗?

解决方案

启用 $type 信息的输出在根级别为带有 的多态对象TypeNameHandling.Auto,使用以下重载:JsonConvert.SerializeObject方法(对象、类型、JsonSerializerSettings).来自 文档:

<块引用>

public static string SerializeObject(对象值,类型,JsonSerializerSettings 设置)

输入类型:System.Type被序列化的值的类型.当TypeNameHandling为Auto时使用该参数,在值的类型不匹配时写出类型名称.指定类型是可选的.

在你的情况下,你会这样做:

var stringA = JsonConvert.SerializeObject(a, typeof(ISample), settings);var stringB = JsonConvert.SerializeObject(b, typeof(ISample), settings);Console.WriteLine(stringA);Console.WriteLine(stringB);

并得到结果:

{"$type":"Tile.TestJsonDotNet.A, Tile","Key":"keyA"}{"$type":"Tile.TestJsonDotNet.B, Tile","Key":"keyB"}

请注意 Newtonsoft 文档中的这一警告:

<块引用>

当您的应用程序从外部源反序列化 JSON 时,应谨慎使用 TypeNameHandling.使用 None 以外的值反序列化时,应使用自定义 SerializationBinder 验证传入类型.

有关为什么需要这样做的讨论,请参阅 Newtonsoft Json 中的 TypeNameHandling 警告如何配置Json.NET 创建易受攻击的 Web API,以及 Alvaro Muñoz &Oleksandr Mirosh 的黑帽论文 https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf

One way of deserializing interface and abstract properties is a class is by setting TypeNameHandling to Auto during serialization and deserialization. However, when I try the same when serializing and deserializing an interface object directly, it does not work -

interface ISample
{
    string Key { get; set; }
}

class A : ISample
{
    public string Key { get; set; }

    public A(string key)
    {
        this.Key = key;
    }
}

class B : ISample
{
    public string Key { get; set; }

    public B(string key)
    {
        this.Key = key;
    }
}

Serialization and deserialization code -

ISample a = new A("keyA");
ISample b = new B("keyB");

var settings = new JsonSerializerSettings();
settings.TypeNameHandling = TypeNameHandling.Auto;

var stringA = JsonConvert.SerializeObject(a, settings);
var stringB = JsonConvert.SerializeObject(b, settings);

Console.WriteLine(stringA);
Console.WriteLine(stringB);

a = JsonConvert.DeserializeObject<ISample>(stringA, settings);
b = JsonConvert.DeserializeObject<ISample>(stringB, settings);

I noticed that even when setting TypeNameHandling.Auto the type information is not present in the serialized string. However, settings TypeNameHandling to Object or All works.

Am I missing something basic here?

解决方案

To enable output of $type information at the root level for a polymorphic object with TypeNameHandling.Auto, use the following overload: JsonConvert.SerializeObject Method (Object, Type, JsonSerializerSettings). From the docs:

public static string SerializeObject(
    Object value,
    Type type,
    JsonSerializerSettings settings
)

type Type: System.Type The type of the value being serialized. This parameter is used when TypeNameHandling is Auto to write out the type name if the type of the value does not match. Specifing the type is optional.

In your case, you would do:

var stringA = JsonConvert.SerializeObject(a, typeof(ISample), settings);
var stringB = JsonConvert.SerializeObject(b, typeof(ISample), settings);

Console.WriteLine(stringA);
Console.WriteLine(stringB);

And get the result:

{"$type":"Tile.TestJsonDotNet.A, Tile","Key":"keyA"}
{"$type":"Tile.TestJsonDotNet.B, Tile","Key":"keyB"}

Do take note of this caution from the Newtonsoft docs:

TypeNameHandling should be used with caution when your application deserializes JSON from an external source. Incoming types should be validated with a custom SerializationBinder when deserializing with a value other than None.

For a discussion of why this may be necessary, see TypeNameHandling caution in Newtonsoft Json, How to configure Json.NET to create a vulnerable web API, and Alvaro Muñoz & Oleksandr Mirosh's blackhat paper https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf

这篇关于使用 NewtonSoft.JSON 序列化接口/抽象对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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