JavaScriptTypeResolver 类

定义

提供用于实现自定义类型解析器的抽象基类。

public ref class JavaScriptTypeResolver abstract
public abstract class JavaScriptTypeResolver
type JavaScriptTypeResolver = class
Public MustInherit Class JavaScriptTypeResolver
继承
JavaScriptTypeResolver
派生

示例

以下示例演示如何创建自定义 JavaScriptTypeResolver 以及如何使用它来序列化或反序列化对象。

using System;
using System.Linq;
using System.Web.Script.Serialization;

namespace SampleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            // The object array to serialize.
            Person[] people = new Person[]
            {
                new Person()
                {
                    Name = "Kristen Solstad",
                    Age = 15,
                    HomeAddress = new Address()
                    {
                        Street1 = "123 Palm Ave",
                        City = "Some City",
                        StateOrProvince = "ST",
                        Country = "United States",
                        PostalCode = "00000"
                    }
                },
                new Adult()
                {
                    Name = "Alex Johnson",
                    Age = 39,
                    Occupation = "Mechanic",
                    HomeAddress = new Address()
                    {
                        Street1 = "445 Lorry Way",
                        Street2 = "Unit 3A",
                        City = "Some City",
                        Country = "United Kingdom",
                        PostalCode = "AA0 A00"
                    }
                }
            };

            // Serialize the object array, then write it to the console.
            string serializedData = SerializePeopleArray(people);
            Console.WriteLine("Serialized:");
            Console.WriteLine(serializedData);
            Console.WriteLine();

            // Now deserialize the object array.
            Person[] deserializedArray = DeserializePeopleArray(serializedData);
            Console.WriteLine("Deserialized " + deserializedArray.Length + " people.");
            foreach (Person person in deserializedArray)
            {
                Console.WriteLine(person.Name + " (Age " + person.Age + ") [" + person.GetType() + "]");
            }
        }

        static string SerializePeopleArray(Person[] people)
        {
            // The custom type resolver to use.
            // Note: Except for primitives like int and string, *every* type that
            // we might see in the object graph must be listed here.
            CustomTypeResolver resolver = new CustomTypeResolver(
                typeof(Person),
                typeof(Adult),
                typeof(Address));

            // Instantiate the serializer.
            JavaScriptSerializer serializer = new JavaScriptSerializer(resolver);

            // Serialize the object array, then return it.
            string serialized = serializer.Serialize(people);
            return serialized;
        }

        static Person[] DeserializePeopleArray(string serializedData)
        {
            // The custom type resolver to use.
            // Note: This is the same list that was provided to the Serialize routine.
            CustomTypeResolver resolver = new CustomTypeResolver(
                typeof(Person),
                typeof(Adult),
                typeof(Address));

            // Instantiate the serializer.
            JavaScriptSerializer serializer = new JavaScriptSerializer(resolver);

            // Deserialize the object array, then return it.
            Person[] deserialized = serializer.Deserialize<Person[]>(serializedData);
            return deserialized;
        }
    }

    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public Address HomeAddress { get; set; }
    }

    public class Adult : Person
    {
        public string Occupation { get; set; }
    }

    public class Address
    {
        public string Street1 { get; set; }
        public string Street2 { get; set; }
        public string City { get; set; }
        public string StateOrProvince { get; set; }
        public string Country { get; set; }
        public string PostalCode { get; set; }
    }

    // A custom JavaScriptTypeResolver that restricts the payload
    // to a set of known good types.
    class CustomTypeResolver : JavaScriptTypeResolver
    {
        private readonly Type[] _allowedTypes;

        public CustomTypeResolver(params Type[] allowedTypes)
        {
            if (allowedTypes == null)
            {
                throw new ArgumentNullException("allowedTypes");
            }

            // Make a copy of the array the caller gave us.
            _allowedTypes = (Type[])allowedTypes.Clone();
        }

        public override Type ResolveType(string id)
        {
            // Iterate over all of the allowed types, looking for a match
            // for the 'id' parameter. Calling Type.GetType(id) is dangerous,
            // so we instead perform a match on the Type.FullName property.
            foreach (Type allowedType in _allowedTypes)
            {
                if (allowedType.FullName == id)
                {
                    return allowedType;
                }
            }

            // The caller provided a type we don't recognize. This could be
            // dangerous, so we'll fail the operation immediately.
            throw new ArgumentException("Unknown type: " + id, "id");
        }

        public override string ResolveTypeId(Type type)
        {
            // Before we serialize data, quickly double-check to make
            // sure we're allowed to deserialize the data. Otherwise it's
            // no good serializing something if we can't deserialize it.
            if (_allowedTypes.Contains(type))
            {
                return type.FullName;
            }

            throw new InvalidOperationException("Cannot serialize an object of type " + type + ". Did you forget to add it to the allow list?");
        }
    }
}

前面的应用将以下内容输出到控制台,其格式为可读性。

Serialized:
[
    {
        "__type": "SampleApp.Person",
        "Name": "Kristen Solstad",
        "Age": 15,
        "HomeAddress": {
            "__type": "SampleApp.Address",
            "Street1": "123 Palm Ave",
            "Street2": null,
            "City": "Some City",
            "StateOrProvince": "ST",
            "Country": "United States",
            "PostalCode": "00000"
        }
    },
    {
        "__type": "SampleApp.Adult",
        "Occupation": "Mechanic",
        "Name": "Alex Johnson",
        "Age": 39,
        "HomeAddress": {
            "__type": "SampleApp.Address",
            "Street1": "445 Lorry Way",
            "Street2": "Unit 3A",
            "City": "Some City",
            "StateOrProvince": null,
            "Country": "United Kingdom",
            "PostalCode": "AA0 A00"
        }
    }
]

Deserialized 2 people.
Kristen Solstad (Age 15) [SampleApp.Person]
Alex Johnson (Age 39) [SampleApp.Adult]

在前面的示例中, Adult 类型对类型进行 Person 子类。 自定义 JavaScriptTypeResolver 用于将类型信息作为生成的 JSON 有效负载的一部分包含在内。 当将 JSON 有效负载反序列化回 .NET 对象图时,这允许有限的多态性。 有效负载可以控制是将基 Person 实例还是派生 Adult 实例返回给调用方。

此示例是安全的,因为它使用一种 allow-list 机制来控制反序列化。 代码:

  • CustomTypeResolver使用允许类型的显式列表初始化 。
  • 将反序列化过程限制为仅批准类型的列表。 此限制可防止 反序列化攻击,其中远程客户端在 JSON 有效负载中指定恶意 __type ,并诱使服务器反序列化危险类型。

尽管应用只要求 PersonAdult 实例作为顶级数组的一部分进行反序列化,但仍需要添加到 Address 允许列表,因为:

  • 序列化 PersonAdult 也序列化 作为对象图的一 Address 部分。
  • 对象图中可能存在的所有类型都需要在允许列表中进行说明。 不需要指定 和 stringint基元。

警告

不要在 ResolveType 方法中调用 Type.GetType(id) 。 这可能会在应用中引入安全可用性。 相反,循环访问允许的类型列表,并将其 Type.FullName 属性与传入 id进行比较,如前面的示例中所示。

注解

JavaScriptTypeResolver 为以下项提供服务:

  • 通过 ResolveTypeId 方法将托管类型信息转换为字符串值。

  • 通过 ResolveType 方法将字符串值解析回适当的托管类型。

JavaScriptSerializer 对象序列化自定义类型时,可以选择在序列化的 JavaScript 对象表示法 (JSON) 字符串中包含一个包含类型信息的值。 在反序列化期间, JavaScriptSerializer 可以引用此字符串值,以确定 JSON 字符串将转换为的相应托管类型。

如果向 JavaScriptSerializer 实例提供类型解析程序,序列化程序将使用 ResolveTypeIdResolveType 方法分别在序列化和反序列化过程中在托管类型和字符串值之间映射。

JavaScriptTypeResolver 是 类的 SimpleTypeResolver 基类,该类提供使用托管类型程序集限定名称的类型解析程序的实现。

注意

使用 JavaScriptTypeResolver时,生成的 JSON 有效负载包含一个特殊 __type 属性。 此属性包括目标类型的完整类型名称(包括命名空间)。 在使用自定义冲突解决程序之前,请验证目标类型的全名是否不包含敏感信息或特权信息。

实施者说明

实现类型解析程序时,当字符串值传递给ResolveType(String)方法时,ResolveTypeId(Type)该方法返回的字符串必须映射回同一托管类型。

构造函数

JavaScriptTypeResolver()

初始化 JavaScriptTypeResolver 类的新实例。

方法

Equals(Object)

确定指定对象是否等于当前对象。

(继承自 Object)
GetHashCode()

作为默认哈希函数。

(继承自 Object)
GetType()

获取当前实例的 Type

(继承自 Object)
MemberwiseClone()

创建当前 Object 的浅表副本。

(继承自 Object)
ResolveType(String)

当在派生类中重写时,返回与指定类型名称相关联的 Type 对象。

ResolveTypeId(Type)

当在派生类中重写时,返回指定的 Type 对象的类型名称。

ToString()

返回表示当前对象的字符串。

(继承自 Object)

适用于