Share via


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 做為物件圖形的一部分。
  • 物件圖形中可能存在的所有類型都必須考慮在允許清單中。 和 之類的 intstring 基本類型不需要指定。

警告

請勿在 ResolveType 方法內呼叫 Type.GetType(id) 。 這可能會在應用程式中引入安全性 vunerability。 相反地,逐一查看允許的類型清單,並比較其 Type.FullName 屬性與傳入 id 的 ,如上述範例所示。

備註

類別 JavaScriptTypeResolver 提供下列服務:

  • 透過 ResolveTypeId 方法將 Managed 型別資訊轉換為字串值。

  • 透過 方法將字串值解析回適當的 Managed 型 ResolveType 別。

JavaScriptSerializer當物件序列化自訂類型時,它可以選擇性地包含在序列化的 JavaScript 物件標記法中, (JSON) 包含類型資訊的值。 在還原序列化期間, JavaScriptSerializer 可以參考此字串值,以判斷要轉換 JSON 字串的適當 Managed 類型。

如果您為 實例提供型別解析程式 JavaScriptSerializer ,序列化程式將會使用 ResolveTypeIdResolveType 方法,分別在序列化和還原序列化程式期間對應 Managed 類型和字串值。

類別 JavaScriptTypeResolver 是 類別的 SimpleTypeResolver 基類,其提供使用 Managed 型別元件限定名稱之型別解析程式的實作。

注意

使用 JavaScriptTypeResolver 時,產生的 JSON 承載會包含特殊 __type 屬性。 此屬性包含目標型別的完整型別名稱,包括命名空間。 使用自訂解析程式之前,請確認目標型別的完整名稱不包含敏感性或特殊許可權資訊。

給實施者的注意事項

當您實作型別解析程式時,方法所傳回的 ResolveTypeId(Type) 字串必須在將字串值傳遞至 方法時對應回 ResolveType(String) 相同的 Managed 型別。

建構函式

JavaScriptTypeResolver()

初始化 JavaScriptTypeResolver 類別的新執行個體。

方法

Equals(Object)

判斷指定的物件是否等於目前的物件。

(繼承來源 Object)
GetHashCode()

做為預設雜湊函式。

(繼承來源 Object)
GetType()

取得目前執行個體的 Type

(繼承來源 Object)
MemberwiseClone()

建立目前 Object 的淺層複製。

(繼承來源 Object)
ResolveType(String)

在衍生類別中覆寫時,傳回與指定之型別名稱相關聯的 Type 物件。

ResolveTypeId(Type)

在衍生類別中覆寫時,會傳回指定之 Type 物件的型別名稱。

ToString()

傳回代表目前物件的字串。

(繼承來源 Object)

適用於