JavaScriptTypeResolver 類別
定義
重要
部分資訊涉及發行前產品,在發行之前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。
提供實作自訂型別解析程式的抽象基底類別。
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
,並讓伺服器將危險類型還原序列化。
即使應用程式只預期 Person
和 Adult
實例會還原序列化為最上層陣列的一部分,但仍需要新增 Address
至允許清單,因為:
- 序列化
Person
或Adult
也會序列化Address
做為物件圖形的一部分。 - 物件圖形中可能存在的所有類型都必須考慮在允許清單中。 和 之類的
int
string
基本類型不需要指定。
警告
請勿在 ResolveType
方法內呼叫 Type.GetType(id)
。 這可能會在應用程式中引入安全性 vunerability。 相反地,逐一查看允許的類型清單,並比較其 Type.FullName
屬性與傳入 id
的 ,如上述範例所示。
備註
類別 JavaScriptTypeResolver 提供下列服務:
透過 ResolveTypeId 方法將 Managed 型別資訊轉換為字串值。
透過 方法將字串值解析回適當的 Managed 型 ResolveType 別。
JavaScriptSerializer當物件序列化自訂類型時,它可以選擇性地包含在序列化的 JavaScript 物件標記法中, (JSON) 包含類型資訊的值。 在還原序列化期間, JavaScriptSerializer 可以參考此字串值,以判斷要轉換 JSON 字串的適當 Managed 類型。
如果您為 實例提供型別解析程式 JavaScriptSerializer ,序列化程式將會使用 ResolveTypeId 和 ResolveType 方法,分別在序列化和還原序列化程式期間對應 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) |