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 を指定し、サーバーを危険な型の逆シリアル化に誘導します。

アプリでは、最上位の配列の一部として Person インスタンスと Adult インスタンスのみが逆シリアル化されることを想定していますが、次の理由から、 Address を許可リストに追加する必要があります。

  • PersonまたはAdultをシリアル化すると、オブジェクト グラフの一部としてAddressもシリアル化されます。
  • オブジェクト グラフに存在する可能性があるすべての型は、許可リストで考慮する必要があります。 intstringなどのプリミティブを指定する必要はありません。

Warning

ResolveType メソッド内でType.GetType(id)を呼び出さないでください。 これにより、アプリにセキュリティの監視機能が導入される可能性があります。 代わりに、許可されている型の一覧を反復処理し、前のサンプルに示すように、 Type.FullName プロパティを受信 idと比較します。

注釈

JavaScriptTypeResolver クラスは、次のサービスを提供します。

  • ResolveTypeId メソッドを使用してマネージド型情報を文字列値に変換する。

  • ResolveType メソッドを使用して、文字列値を適切なマネージド型に解決します。

JavaScriptSerializer オブジェクトは、カスタム型をシリアル化するときに、必要に応じて、シリアル化された JavaScript Object Notation (JSON) 文字列に型情報を含む値を含めることができます。 逆シリアル化中、 JavaScriptSerializer はこの文字列値を参照して、JSON 文字列の変換先となる適切なマネージド型を決定できます。

JavaScriptSerializer インスタンスに型リゾルバーを指定した場合、シリアライザーは、ResolveTypeIdメソッドとResolveType メソッドを使用して、シリアル化および逆シリアル化プロセス中にマネージド型と文字列値の間でマップします。

JavaScriptTypeResolver クラスは、マネージド型アセンブリ修飾名を使用する型リゾルバーの実装を提供する、SimpleTypeResolver クラスの基底クラスです。

Note

JavaScriptTypeResolverを使用する場合、結果の JSON ペイロードには特別な__type プロパティが含まれます。 このプロパティには、ターゲット型の名前空間を含む完全な型名が含まれます。 カスタム 競合回避モジュールを使用する前に、対象の種類の完全な名前に機密情報または特権情報が含まれていないことを確認します。

注意 (実装者)

型リゾルバーを実装する場合、 ResolveTypeId(Type) メソッドによって返される文字列は、文字列値が ResolveType(String) メソッドに渡されるときに、同じマネージド型にマップし直す必要があります。

コンストラクター

名前 説明
JavaScriptTypeResolver()

JavaScriptTypeResolver クラスの新しいインスタンスを初期化します。

メソッド

名前 説明
Equals(Object)

指定したオブジェクトが現在のオブジェクトと等しいかどうかを判断します。

(継承元 Object)
GetHashCode()

既定のハッシュ関数として機能します。

(継承元 Object)
GetType()

現在のインスタンスの Type を取得します。

(継承元 Object)
MemberwiseClone()

現在の Objectの簡易コピーを作成します。

(継承元 Object)
ResolveType(String)

派生クラスでオーバーライドされると、指定した型名に関連付けられている Type オブジェクトを返します。

ResolveTypeId(Type)

派生クラスでオーバーライドされると、指定した Type オブジェクトの型名を返します。

ToString()

現在のオブジェクトを表す文字列を返します。

(継承元 Object)

適用対象