Share via


JavaScriptTypeResolver Clase

Definición

Proporciona la clase base abstracta para implementar una resolución personalizada de tipos.

public ref class JavaScriptTypeResolver abstract
public abstract class JavaScriptTypeResolver
type JavaScriptTypeResolver = class
Public MustInherit Class JavaScriptTypeResolver
Herencia
JavaScriptTypeResolver
Derivado

Ejemplos

En el ejemplo siguiente se muestra cómo crear un personalizado JavaScriptTypeResolver y cómo usarlo para serializar o deserializar un objeto.

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?");
        }
    }
}

La aplicación anterior genera lo siguiente en la consola, con el formato de legibilidad.

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]

En el ejemplo anterior, el Adult tipo subclase el Person tipo. Se usa un personalizado JavaScriptTypeResolver para incluir la información de tipo como parte de la carga JSON generada. Esto permite un polimorfismo limitado al deserializar la carga JSON en un gráfico de objetos de .NET. La carga puede controlar si se devuelve una instancia base Person o una instancia derivada Adult al autor de la llamada.

Este ejemplo es seguro porque usa un allow-list mecanismo para controlar la deserialización. El código:

  • Inicializa con una lista explícita de tipos permitidos CustomTypeResolver .
  • Restringe el proceso de deserialización solo a la lista aprobada de tipos. La restricción evita ataques de deserialización, donde el cliente remoto especifica un malintencionado __type en la carga JSON y engaña al servidor para deserializar un tipo peligroso.

Aunque la aplicación solo espera Person que las instancias y Adult se deserialicen como parte de la matriz de nivel superior, sigue siendo necesario agregar Address a la lista de permitidos porque:

  • Serializar o PersonAdult también serializa como Address parte del gráfico de objetos.
  • Todos los tipos que podrían estar presentes en el gráfico de objetos deben tener en cuenta en la lista de permitidos. No es necesario especificar primitivos como int y string .

Advertencia

No llame al Type.GetType(id)ResolveType método . Esto podría introducir una capacidad de recuperación de seguridad en la aplicación. En su lugar, recorra en iteración la lista de tipos permitidos y compare su Type.FullName propiedad con el entrante id, como se muestra en el ejemplo anterior.

Comentarios

La JavaScriptTypeResolver clase proporciona los servicios para:

  • Convertir la información de tipo administrado en un valor de cadena a través del ResolveTypeId método .

  • Resolver un valor de cadena de vuelta al tipo administrado adecuado a través del ResolveType método .

Cuando el JavaScriptSerializer objeto serializa los tipos personalizados, opcionalmente puede incluir en la cadena serializada de notación de objetos JavaScript (JSON) un valor que contiene información de tipo. Durante la deserialización, JavaScriptSerializer puede hacer referencia a este valor de cadena para determinar el tipo administrado adecuado al que se convertirá la cadena JSON.

Si proporciona una resolución de tipos a la JavaScriptSerializer instancia, el serializador usará los ResolveTypeId métodos y ResolveType para asignar entre el tipo administrado y el valor de cadena durante el proceso de serialización y deserialización, respectivamente.

La JavaScriptTypeResolver clase es la clase base de la SimpleTypeResolver clase , que proporciona una implementación de un solucionador de tipos que usa el nombre completo del ensamblado de tipo administrado.

Nota

Cuando se usa , JavaScriptTypeResolverla carga JSON resultante contiene una propiedad especial __type . Esta propiedad incluye el nombre de tipo completo, incluido el espacio de nombres, del tipo de destino. Antes de usar una resolución personalizada, compruebe que el nombre completo del tipo de destino no contiene información confidencial o con privilegios.

Notas a los implementadores

Al implementar una resolución de tipos, la cadena devuelta por el ResolveTypeId(Type) método debe volver a asignarse al mismo tipo administrado cuando el valor de cadena se pasa al ResolveType(String) método .

Constructores

JavaScriptTypeResolver()

Inicializa una nueva instancia de la clase JavaScriptTypeResolver.

Métodos

Equals(Object)

Determina si el objeto especificado es igual que el objeto actual.

(Heredado de Object)
GetHashCode()

Sirve como la función hash predeterminada.

(Heredado de Object)
GetType()

Obtiene el Type de la instancia actual.

(Heredado de Object)
MemberwiseClone()

Crea una copia superficial del Object actual.

(Heredado de Object)
ResolveType(String)

Cuando se invalida en una clase derivada, devuelve el objeto Type asociado al nombre de tipo especificado.

ResolveTypeId(Type)

Cuando se invalida en una clase derivada, devuelve el nombre de tipo del objeto Type especificado.

ToString()

Devuelve una cadena que representa el objeto actual.

(Heredado de Object)

Se aplica a