Serialización y deserializaciónSerialization and Deserialization

Windows Communication Foundation (WCF) incluye un nuevo motor de serialización, DataContractSerializerel.Windows Communication Foundation (WCF) includes a new serialization engine, the DataContractSerializer. DataContractSerializer Traduce entre .NET Framework objetos y XML, en ambas direcciones.The DataContractSerializer translates between .NET Framework objects and XML, in both directions. En este tema se explica cómo funciona el serializador.This topic explains how the serializer works.

Al serializar .NET Framework objetos, el serializador entiende diversos modelos de programación de la serialización, incluido el nuevo modelo de contrato de datos .When serializing .NET Framework objects, the serializer understands a variety of serialization programming models, including the new data contract model. Para obtener una lista completa de los tipos admitidos, consulte Types Supported by the Data Contract Serializer.For a full list of supported types, see Types Supported by the Data Contract Serializer. Para obtener una introducción a los contratos de datos, consulte Using Data Contracts.For an introduction to data contracts, see Using Data Contracts.

Al deserializar XML, el serializador utiliza las clases XmlReader y XmlWriter .When deserializing XML, the serializer uses the XmlReader and XmlWriter classes. También admite las XmlDictionaryReader clases y XmlDictionaryWriter para permitirle generar XML optimizado en algunos casos, como cuando se usa el formato XML binario WCF.It also supports the XmlDictionaryReader and XmlDictionaryWriter classes to enable it to produce optimized XML in some cases, such as when using the WCF binary XML format.

WCF también incluye un serializador complementario, NetDataContractSerializerel.WCF also includes a companion serializer, the NetDataContractSerializer. Es similar a los BinaryFormatter serializadores SoapFormatter y porque también emite .NET Framework nombres de tipo como parte de los datos serializados. NetDataContractSerializerThe NetDataContractSerializer is similar to the BinaryFormatter and SoapFormatter serializers because it also emits .NET Framework type names as part of the serialized data. Se utiliza cuando se comparten los mismos tipos en los extremos de serialización y deserialización.It is used when the same types are shared on the serializing and the deserializing ends. DataContractSerializer y NetDataContractSerializer derivan de una clase base común, XmlObjectSerializer.Both the DataContractSerializer and the NetDataContractSerializer derive from a common base class, the XmlObjectSerializer.

Advertencia

DataContractSerializer serializa cadenas que contienen caracteres de control con un valor hexadecimal inferior a 20 como entidades XML.The DataContractSerializer serializes strings containing control characters with a hexadecimal value below 20 as XML entities. Esto puede producir un problema con un cliente que no sea de WCF al enviar estos datos a un servicio WCF.This may cause a problem with a non-WCF client when sending such data to a WCF service.

Creación de una instancia de DataContractSerializerCreating a DataContractSerializer Instance

Construir una instancia de DataContractSerializer es un paso importante.Constructing an instance of the DataContractSerializer is an important step. Después de la construcción no puede cambiar ninguno de los valores.After construction, you cannot change any of the settings.

Especificación del tipo de raízSpecifying the Root Type

El tipo de raíz es el tipo en el que las instancias se serializan o deserializan.The root type is the type of which instances are serialized or deserialized. DataContractSerializer tiene muchas sobrecarga del constructor, pero, como mínimo, se debe proporcionar un tipo de raíz utilizando el parámetro type .The DataContractSerializer has many constructor overloads, but, at a minimum, a root type must be supplied using the type parameter.

Un serializador creado para un tipo de raíz determinado no se puede utilizar para serializar (o deserializar) otro tipo, a menos que el tipo se derive del tipo de raíz.A serializer created for a certain root type cannot be used to serialize (or deserialize) another type, unless the type is derived from the root type. En el ejemplo siguiente se muestran dos clases.The following example shows two classes.

[DataContract]
public class Person
{
    // Code not shown.
}

[DataContract]
public class PurchaseOrder
{
    // Code not shown.
}
<DataContract()> _
Public Class Person
    ' Code not shown.
End Class 

<DataContract()> _
Public Class PurchaseOrder
    ' Code not shown.
End Class 

Este código construye una instancia del DataContractSerializer que solo se puede utilizar para serializar o deserializar instancias de la clase Person .This code constructs an instance of the DataContractSerializer that can be used only to serialize or deserialize instances of the Person class.

DataContractSerializer dcs = new DataContractSerializer(typeof(Person));
// This can now be used to serialize/deserialize Person but not PurchaseOrder.
Dim dcs As New DataContractSerializer(GetType(Person))
' This can now be used to serialize/deserialize Person but not PurchaseOrder.

Especificación de los tipos conocidosSpecifying Known Types

Si el polimorfismo está implicado en los tipos que se están serializando que aún no se administran usando el atributo KnownTypeAttribute o algún otro mecanismo, se ha de pasar una lista de posibles tipos conocidos al constructor del serializador usando el parámetro knownTypes .If polymorphism is involved in the types being serialized that is not already handled using the KnownTypeAttribute attribute or some other mechanism, a list of possible known types must be passed to the serializer’s constructor using the knownTypes parameter. Para obtener más información sobre los tipos conocidos, consulte Data Contract known Types.For more information about known types, see Data Contract Known Types.

El siguiente ejemplo muestra una clase, LibraryPatron, que incluye una colección de un tipo específico, LibraryItem.The following example shows a class, LibraryPatron, that includes a collection of a specific type, the LibraryItem. La segunda clase define el tipo LibraryItem .The second class defines the LibraryItem type. Las clases tercera y cuartaBook y Newspaperheredan de la clase LibraryItem .The third and four classes (Book and Newspaper) inherit from the LibraryItem class.

[DataContract]
public class LibraryPatron
{
    [DataMember]
    public LibraryItem[] borrowedItems;
}
[DataContract]
public class LibraryItem
{
    // Code not shown.
}

[DataContract]
public class Book : LibraryItem
{
    // Code not shown.
}

[DataContract]
public class Newspaper : LibraryItem
{
    // Code not shown.
}
<DataContract()>  _
Public Class LibraryPatron
    <DataMember()> _
    Public borrowedItems() As LibraryItem
End Class 

<DataContract()>  _
Public Class LibraryItem
   ' Code not shown.
End Class

<DataContract()>  _
Public Class Book
    Inherits LibraryItem
    ' Code not shown.
End Class 

<DataContract()>  _
Public Class Newspaper
    Inherits LibraryItem
    ' Code not shown.
End Class 

El siguiente código construye una instancia del serializador utilizando el parámetro knownTypes .The following code constructs an instance of the serializer using the knownTypes parameter.

// Create a serializer for the inherited types using the knownType parameter.
Type[] knownTypes = new Type[] { typeof(Book), typeof(Newspaper) };
DataContractSerializer dcs =
new DataContractSerializer(typeof(LibraryPatron), knownTypes);
// All types are known after construction.
' Create a serializer for the inherited types using the knownType parameter.
Dim knownTypes() As Type = {GetType(Book), GetType(Newspaper)}
Dim dcs As New DataContractSerializer(GetType(LibraryPatron), knownTypes)
' All types are known after construction.

Especificación del espacio de nombres y el nombre de raíz predeterminadosSpecifying the Default Root Name and Namespace

Normalmente, cuando se serializa un objeto, el nombre y espacio de nombres predeterminados del elemento XML extremo se determinan según el nombre y el espacio de nombres del contrato de datos.Normally, when an object is serialized, the default name and namespace of the outermost XML element are determined according to the data contract name and namespace. Los nombres de todos los elementos internos se determinan a partir de los nombres de los miembros de datos y su espacio de nombres es el espacio de nombres del contrato de datos.The names of all inner elements are determined from data member names, and their namespace is the data contract’s namespace. El siguiente ejemplo establece los valores de Name y Namespace en los constructores de las clases DataContractAttribute y DataMemberAttribute .The following example sets Name and Namespace values in the constructors of the DataContractAttribute and DataMemberAttribute classes.

[DataContract(Name = "PersonContract", Namespace = "http://schemas.contoso.com")]
public class Person2
{
    [DataMember(Name = "AddressMember")]
    public Address theAddress;
}

[DataContract(Name = "AddressContract", Namespace = "http://schemas.contoso.com")]
public class Address
{
    [DataMember(Name = "StreetMember")]
    public string street;
}
<DataContract(Name := "PersonContract", [Namespace] := "http://schemas.contoso.com")>  _
Public Class Person2
    <DataMember(Name := "AddressMember")>  _
    Public theAddress As Address
End Class 

<DataContract(Name := "AddressContract", [Namespace] := "http://schemas.contoso.com")>  _
Public Class Address
    <DataMember(Name := "StreetMember")>  _
    Public street As String
End Class 

Al serializar una instancia de la clase Person , se genera código XML similar al siguiente.Serializing an instance of the Person class produces XML similar to the following.

<PersonContract xmlns="http://schemas.contoso.com">  
  <AddressMember>  
    <StreetMember>123 Main Street</StreetMember>  
   </AddressMember>  
</PersonContract>  

Sin embargo, puede personalizar el nombre y espacio de nombres predeterminado del elemento raíz pasando los valores de los parámetros rootName y rootNamespace al constructor DataContractSerializer .However, you can customize the default name and namespace of the root element by passing the values of the rootName and rootNamespace parameters to the DataContractSerializer constructor. Observe que el rootNamespace no afecta al espacio de nombres de los elementos contenidos que corresponden a miembros de datos.Note that the rootNamespace does not affect the namespace of the contained elements that correspond to data members. Solo afecta al espacio de nombres del elemento extremo.It affects only the namespace of the outermost element.

Estos valores se pueden pasar como cadenas o instancias de la clase XmlDictionaryString para permitir su optimización mediante el formato XML binario.These values can be passed as strings or instances of the XmlDictionaryString class to allow for their optimization using the binary XML format.

Establecimiento de la cuota de objetos máximosSetting the Maximum Objects Quota

Algunas sobrecargas del constructor de DataContractSerializer tienen un parámetro maxItemsInObjectGraph .Some DataContractSerializer constructor overloads have a maxItemsInObjectGraph parameter. Este parámetro determina el número máximo de objetos que el serializador serializa o deserializa en una única llamada al método ReadObject .This parameter determines the maximum number of objects the serializer serializes or deserializes in a single ReadObject method call. (El método siempre lee un objeto raíz, pero este objeto puede tener otros objetos en sus miembros de datos.(The method always reads one root object, but this object may have other objects in its data members. Esos objetos pueden tener otros objetos, etc.) El valor predeterminado es 65536.Those objects may have other objects, and so on.) The default is 65536. Tenga en cuenta que al serializar o deserializar las matrices, cada entrada de matriz cuenta como un objeto independiente.Note that when serializing or deserializing arrays, every array entry counts as a separate object. Observe también que algunos objetos pueden tener una representación de memoria grande, por lo que esta cuota por sí sola puede no ser suficiente para evitar ataques por denegación de servicio.Also, note that some objects may have a large memory representation, and so this quota alone may not be sufficient to prevent a denial of service attack. Para obtener más información, vea consideraciones de seguridad para los datos.For more information, see Security Considerations for Data. Si necesita aumentar esta cuota por encima del valor predeterminado, es importante hacerlo en los lados de envío (serialización) y recepción (deserialización), porque se aplica a ambos al leer y escribir datos.If you need to increase this quota beyond the default value, it is important to do so both on the sending (serializing) and receiving (deserializing) sides because it applies to both when reading and writing data.

Acciones de ida y vueltaRound Trips

Una acción de ida y vuelta (round trip) se produce cuando un objeto se deserializa y se vuelve a serializar en una operación.A round trip occurs when an object is deserialized and re-serialized in one operation. De este modo, va de XML a una instancia de objeto y de vuelta a una secuencia XML.Thus, it goes from XML to an object instance, and back again into an XML stream.

Algunas sobrecargas del constructor del DataContractSerializer tienen un parámetro ignoreExtensionDataObject , que está establecido de forma predeterminada en false .Some DataContractSerializer constructor overloads have an ignoreExtensionDataObject parameter, which is set to false by default. En este modo predeterminado, los datos se pueden enviar en un viaje de ida y vuelta (round trip) desde una versión más reciente de un contrato de datos a través de una versión anterior y de vuelta a la versión más reciente sin pérdidas, siempre que el contrato de datos implemente la interfaz IExtensibleDataObject .In this default mode, data can be sent on a round trip from a newer version of a data contract through an older version and back to the newer version without loss, as long as the data contract implements the IExtensibleDataObject interface. Por ejemplo, suponga que la versión 1 del contrato de datos de la Person contiene los miembros de datos Name y PhoneNumber , y la versión 2 agrega un miembro Nickname .For example, suppose version 1 of the Person data contract contains the Name and PhoneNumber data members, and version 2 adds a Nickname member. Si se implementa IExtensibleDataObject al enviar información de la versión 2 a la versión 1, los datos Nickname se almacenan y, a continuación, se vuelven a emitir cuando se vuelven a serializar los datos; por tanto, no se pierden datos en el viaje de ida y vuelta.If IExtensibleDataObject is implemented, when sending information from version 2 to version 1, the Nickname data is stored, and then re-emitted when the data is serialized again; therefore, no data is lost in the round trip. Para obtener más información, consulte los contratos de datos compatibles con el avance y el control de versiones del contrato de datos.For more information, see Forward-Compatible Data Contracts and Data Contract Versioning.

Aspectos a tener en cuenta sobre seguridad y validez del esquema en relación con los viajes de ida y vuelta (round trip)Security and Schema Validity Concerns with Round Trips

Los viajes de ida y vuelta pueden tener implicaciones en cuanto a la seguridad.Round trips may have security implications. Por ejemplo, deserializar y almacenar grandes cantidades de datos extraños puede constituir un riesgo para la seguridad.For example, deserializing and storing large amounts of extraneous data may be a security risk. Puede haber problemas de seguridad al reemitir estos datos que no se pueden comprobar, sobre todo si hay firmas digitales implicadas.There may be security concerns about re-emitting this data that there is no way to verify, especially if digital signatures are involved. Por ejemplo, en el escenario anterior, el extremo de versión 1 podría estar firmando un valor Nickname que contuviese datos malintencionados.For example, in the previous scenario, the version 1 endpoint could be signing a Nickname value that contains malicious data. Por último, puede haber problemas de validez del esquema: un extremo puede desear emitir siempre datos que cumplan de manera estricta el contrato indicado y no valores adicionales.Finally, there may be schema validity concerns: an endpoint may want to always emit data that strictly adheres to its stated contract and not any extra values. En el ejemplo anterior, el contrato del extremo de versión 1 dice que solo emite Name y PhoneNumber, y si se utiliza la validación de esquema, se produciría un error de validación al emitir el valor Nickname adicional.In the previous example, the version 1 endpoint’s contract says that it emits only Name and PhoneNumber, and if schema validation is being used, emitting the extra Nickname value causes validation to fail.

Habilitar y deshabilitar los viajes de ida y vueltaEnabling and Disabling Round Trips

Para desactivar los viajes de ida y vuelta, no implemente la interfaz IExtensibleDataObject .To turn off round trips, do not implement the IExtensibleDataObject interface. Si no tiene ningún control sobre los tipos, establezca el parámetro ignoreExtensionDataObject en true para lograr el mismo efecto.If you have no control over the types, set the ignoreExtensionDataObject parameter to true to achieve the same effect.

Preservación de gráfico de objetoObject Graph Preservation

Normalmente, el serializador no se preocupa de la identidad del objeto, como en el código siguiente.Normally, the serializer does not care about object identity, as in the following code.

[DataContract]
public class PurchaseOrder
{
    [DataMember]
    public Address billTo;
    [DataMember]
    public Address shipTo;
}

[DataContract]
public class Address
{
    [DataMember]
    public string street;
}
<DataContract()>  _
Public Class PurchaseOrder

    <DataMember()>  _
    Public billTo As Address

    <DataMember()>  _
    Public shipTo As Address

End Class 

<DataContract()>  _
Public Class Address

    <DataMember()>  _
    Public street As String

End Class 

El siguiente código crea un pedido de compra.The following code creates a purchase order.

// Construct a purchase order:
Address adr = new Address();
adr.street = "123 Main St.";
PurchaseOrder po = new PurchaseOrder();
po.billTo = adr;
po.shipTo = adr;
' Construct a purchase order:
Dim adr As New Address()
adr.street = "123 Main St."
Dim po As New PurchaseOrder()
po.billTo = adr
po.shipTo = adr

Observe que los campos billTo y shipTo están establecidos en la misma instancia de objeto.Notice that billTo and shipTo fields are set to the same object instance. Sin embargo, el XML generado duplica la información duplicada y parece similar al siguiente XML.However, the generated XML duplicates the information duplicated, and looks similar to the following XML.

<PurchaseOrder>  
  <billTo><street>123 Main St.</street></billTo>  
  <shipTo><street>123 Main St.</street></shipTo>  
</PurchaseOrder>  

Sin embargo, este enfoque tiene las siguientes características, que puede que no se deseen:However, this approach has the following characteristics, which may be undesirable:

  • Rendimiento.Performance. La replicación de datos es ineficaz.Replicating data is inefficient.

  • Referencias circulares.Circular references. Si los objetos hacen referencia a ellos mismos, incluso a través de otros objetos, la serialización mediante resultados de replicación resulta en un bucle infinito.If objects refer to themselves, even through other objects, serializing by replication results in an infinite loop. (Si esto sucede, el serializador inicia una SerializationException .)(The serializer throws a SerializationException if this happens.)

  • Semántica.Semantics. A veces es importante conservar el hecho de que se realicen dos referencias al mismo objeto, y no a dos objetos idénticos.Sometimes it is important to preserve the fact that two references are to the same object, and not to two identical objects.

Por estas razones, algunas sobrecargas del constructor de DataContractSerializer tienen un parámetro preserveObjectReferences (el valor predeterminado es false).For these reasons, some DataContractSerializer constructor overloads have a preserveObjectReferences parameter (the default is false). Cuando este parámetro se establece en true, se usa un método especial de codificación de referencias de objeto, que solo es compatible con WCF.When this parameter is set to true, a special method of encoding object references, which only WCF understands, is used. Cuando se establece en true, el ejemplo de código XML tiene ahora el siguiente aspecto.When set to true, the XML code example now resembles the following.

<PurchaseOrder ser:id="1">  
  <billTo ser:id="2"><street ser:id="3">123 Main St.</street></billTo>  
  <shipTo ser:ref="2"/>  
</PurchaseOrder>  

El espacio de nombres "ser" hace referencia al espacio de nombres http://schemas.microsoft.com/2003/10/Serialization/de serialización estándar,.The "ser" namespace refers to the standard serialization namespace, http://schemas.microsoft.com/2003/10/Serialization/. Cada parte de datos se serializa solo una vez y se proporciona un número de identificador a cada una de esas partes de datos, y los posteriores usos resultan en una referencia a los datos ya serializados.Each piece of data is serialized only once and given an ID number, and subsequent uses result in a reference to the already serialized data.

Importante

Si los atributos "id" y "ref" están presentes en el elemento XMLElementdel contrato de datos, se observa el atributo "ref" y se omite "id".If both "id" and "ref" attributes are present in the data contract XMLElement, then the "ref" attribute is honored and the "id" attribute is ignored.

Es importante conocer las limitaciones de este modo:It is important to understand the limitations of this mode:

  • El XML que produce el DataContractSerializer con preserveObjectReferences establecido en true no es interoperable con ninguna otra tecnología y solo puede obtenerse acceso a él mediante otra instancia del DataContractSerializer , también con preserveObjectReferences establecido en true.The XML the DataContractSerializer produces with preserveObjectReferences set to true is not interoperable with any other technologies, and can be accessed only by another DataContractSerializer instance, also with preserveObjectReferences set to true.

  • No hay compatibilidad con metadatos (esquema) para esta característica.There is no metadata (schema) support for this feature. El esquema que se genera solo es válido para el caso en que preserveObjectReferences está establecido en false.The schema that is produced is valid only for the case when preserveObjectReferences is set to false.

  • Esta característica puede hacer que el proceso de serialización y deserialización se ejecuten más lentamente.This feature may cause the serialization and deserialization process to run slower. Aunque los datos no tienen que replicarse, las comparaciones con objetos adicionales se deben realizar en este modo.Although data does not have to be replicated, extra object comparisons must be performed in this mode.

Precaución

Cuando se habilita el modo preserveObjectReferences , es especialmente importante establecer el valor maxItemsInObjectGraph en la cuota correcta.When the preserveObjectReferences mode is enabled, it is especially important to set the maxItemsInObjectGraph value to the correct quota. Debido a la manera en la que se administran las matrices en este modo, es fácil que un atacante construya un pequeño mensaje malintencionado que provoque un uso de memoria grande limitado únicamente por la cuota maxItemsInObjectGraph .Due to the way arrays are handled in this mode, it is easy for an attacker to construct a small malicious message that results in large memory consumption limited only by the maxItemsInObjectGraph quota.

Especificación de un contrato de datos suplenteSpecifying a Data Contract Surrogate

Algunas sobrecargas del constructor del DataContractSerializer tienen un parámetro dataContractSurrogate , que se puede establecer en null.Some DataContractSerializer constructor overloads have a dataContractSurrogate parameter, which may be set to null. De lo contrario, puede utilizarlo para especificar un contrato de datos suplente, que es un tipo que implementa la interfaz IDataContractSurrogate .Otherwise, you can use it to specify a data contract surrogate, which is a type that implements the IDataContractSurrogate interface. Puede utilizar a continuación la interfaz para personalizar el proceso de serialización y deserialización.You can then use the interface to customize the serialization and deserialization process. Para obtener más información, vea suplentes del contrato de datos.For more information, see Data Contract Surrogates.

SerializaciónSerialization

La siguiente información se aplica a cualquier clase que herede del XmlObjectSerializer,incluido las clases DataContractSerializer y NetDataContractSerializer .The following information applies to any class that inherits from the XmlObjectSerializer, including the DataContractSerializer and NetDataContractSerializer classes.

Serialización simpleSimple Serialization

La manera más básica de serializar un objeto es pasarlo al método WriteObject .The most basic way to serialize an object is to pass it to the WriteObject method. Hay tres sobrecargas, que permiten escribir en una Stream, un XmlWritero un XmlDictionaryWriter.There are three overloads, one each for writing to a Stream, an XmlWriter, or an XmlDictionaryWriter. Con la sobrecarga Stream , el resultado es XML en la codificación UTF-8.With the Stream overload, the output is XML in the UTF-8 encoding. Con la sobrecarga XmlDictionaryWriter , el serializador optimiza su resultado para XML binario.With the XmlDictionaryWriter overload, the serializer optimizes its output for binary XML.

Cuando se usa WriteObject el método, el serializador utiliza el nombre y espacio de nombres predeterminados para el elemento contenedor y lo escribe junto con el contenido (vea la sección anterior "Especificación del nombre y espacio de nombres raíz predeterminados").When using the WriteObject method, the serializer uses the default name and namespace for the wrapper element and writes it out along with the contents (see the previous "Specifying the Default Root Name and Namespace" section).

En el ejemplo siguiente se muestra la escritura con XmlDictionaryWriter.The following example demonstrates writing with an XmlDictionaryWriter.

Person p = new Person();
DataContractSerializer dcs =
    new DataContractSerializer(typeof(Person));
XmlDictionaryWriter xdw =
    XmlDictionaryWriter.CreateTextWriter(someStream,Encoding.UTF8 );
dcs.WriteObject(xdw, p);
Dim p As New Person()
Dim dcs As New DataContractSerializer(GetType(Person))
Dim xdw As XmlDictionaryWriter = _
    XmlDictionaryWriter.CreateTextWriter(someStream, Encoding.UTF8)
dcs.WriteObject(xdw, p)

Esto produce un XML similar al siguiente.This produces XML similar to the following.

<Person>  
  <Name>Jay Hamlin</Name>  
  <Address>123 Main St.</Address>  
</Person>  

Serialización paso a pasoStep-By-Step Serialization

Utilice los métodos WriteStartObject, WriteObjectContenty WriteEndObject para escribir el elemento de fin, escribir el contenido del objeto y cerrar el elemento contenedor, respectivamente.Use the WriteStartObject, WriteObjectContent, and WriteEndObject methods to write the end element, write the object contents, and close the wrapper element, respectively.

Nota

No hay ninguna sobrecarga Stream de estos métodos.There are no Stream overloads of these methods.

Esta serialización paso a paso tiene dos usos extendidos.This step-by-step serialization has two common uses. Uno consiste en insertar contenido como atributos o comentarios entre WriteStartObject y WriteObjectContent, tal y como se muestra en el siguiente ejemplo.One is to insert contents such as attributes or comments between WriteStartObject and WriteObjectContent, as shown in the following example.

dcs.WriteStartObject(xdw, p);
xdw.WriteAttributeString("serializedBy", "myCode");
dcs.WriteObjectContent(xdw, p);
dcs.WriteEndObject(xdw);
dcs.WriteStartObject(xdw, p)
xdw.WriteAttributeString("serializedBy", "myCode")
dcs.WriteObjectContent(xdw, p)
dcs.WriteEndObject(xdw)

Esto produce un XML similar al siguiente.This produces XML similar to the following.

<Person serializedBy="myCode">  
  <Name>Jay Hamlin</Name>  
  <Address>123 Main St.</Address>  
</Person>  

Otro uso común consiste en evitar utilizar WriteStartObject y WriteEndObject por completo, y escribir su propio elemento contenedor personalizado (o incluso pasar por alto totalmente la escritura de un contenedor), tal y como se muestra en el siguiente código.Another common use is to avoid using WriteStartObject and WriteEndObject entirely, and to write your own custom wrapper element (or even skip writing a wrapper altogether), as shown in the following code.

xdw.WriteStartElement("MyCustomWrapper");
dcs.WriteObjectContent(xdw, p);
xdw.WriteEndElement();
xdw.WriteStartElement("MyCustomWrapper")
dcs.WriteObjectContent(xdw, p)
xdw.WriteEndElement()

Esto produce un XML similar al siguiente.This produces XML similar to the following.

<MyCustomWrapper>  
  <Name>Jay Hamlin</Name>  
  <Address>123 Main St.</Address>  
</MyCustomWrapper>  

Nota

El uso de la serialización paso a paso puede producir un XML de esquema no válido.Using step-by-step serialization may result in schema-invalid XML.

DeserializaciónDeserialization

La siguiente información se aplica a cualquier clase que herede del XmlObjectSerializer,incluido las clases DataContractSerializer y NetDataContractSerializer .The following information applies to any class that inherits from the XmlObjectSerializer, including the DataContractSerializer and NetDataContractSerializer classes.

La manera más básica de deserializar un objeto consiste en llamar a una de las sobrecargas del método ReadObject .The most basic way to deserialize an object is to call one of the ReadObject method overloads. Hay tres sobrecargas, que permiten leer con un XmlDictionaryReader, un XmlReadero una Stream.There are three overloads, one each for reading with a XmlDictionaryReader, an XmlReader, or a Stream. Observe que la sobrecarga Stream crea un XmlDictionaryReader textual que no está protegido por ninguna cuota, por lo que solo debería utilizarse para leer datos de confianza.Note that the Stream overload creates a textual XmlDictionaryReader that is not protected by any quotas, and should be used only to read trusted data.

También tenga en cuenta que el objeto que devuelve el método ReadObject debe convertirse al tipo adecuado.Also note that the object the ReadObject method returns must be cast to the appropriate type.

El siguiente código construye una instancia de DataContractSerializer y XmlDictionaryReader, a continuación, deserializa una instancia de Person .The following code constructs an instance of the DataContractSerializer and an XmlDictionaryReader, then deserializes a Person instance.

DataContractSerializer dcs = new DataContractSerializer(typeof(Person));
FileStream fs = new FileStream(path, FileMode.Open);
XmlDictionaryReader reader =
XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());

Person p = (Person)dcs.ReadObject(reader);
Dim dcs As New DataContractSerializer(GetType(Person))
Dim fs As New FileStream(path, FileMode.Open)
Dim reader As XmlDictionaryReader = _
   XmlDictionaryReader.CreateTextReader(fs, New XmlDictionaryReaderQuotas())

Dim p As Person = CType(dcs.ReadObject(reader), Person)

Antes de llamar al método ReadObject , coloque el lector XML en el elemento contenedor o en un nodo de no contenido que preceda al elemento contenedor.Before calling the ReadObject method, position the XML reader on the wrapper element or on a non-content node that precedes the wrapper element. Puede realizar esto llamando al método Read del XmlReader o su derivación y probando NodeType, tal y como se muestra en el código siguiente.You can do this by calling the Read method of the XmlReader or its derivation, and testing the NodeType, as shown in the following code.

DataContractSerializer ser = new DataContractSerializer(typeof(Person),
"Customer", @"http://www.contoso.com");
FileStream fs = new FileStream(path, FileMode.Open);
XmlDictionaryReader reader =
XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
while (reader.Read())
{
    switch (reader.NodeType)
    {
        case XmlNodeType.Element:
            if (ser.IsStartObject(reader))
            {
                Console.WriteLine("Found the element");
                Person p = (Person)ser.ReadObject(reader);
                Console.WriteLine("{0} {1}    id:{2}",
                    p.Name , p.Address);
            }
            Console.WriteLine(reader.Name);
            break;
    }
}
Dim ser As New DataContractSerializer(GetType(Person), "Customer", "http://www.contoso.com")
Dim fs As New FileStream(path, FileMode.Open)
Dim reader As XmlDictionaryReader = XmlDictionaryReader.CreateTextReader(fs, New XmlDictionaryReaderQuotas())

While reader.Read()
    Select Case reader.NodeType
        Case XmlNodeType.Element
            If ser.IsStartObject(reader) Then
                Console.WriteLine("Found the element")
                Dim p As Person = CType(ser.ReadObject(reader), Person)
                Console.WriteLine("{0} {1}", _
                                   p.Name, p.Address)
            End If
            Console.WriteLine(reader.Name)
    End Select
End While

Observe que puede leer atributos en este elemento contenedor antes de entregar el lector a ReadObject.Note that you can read attributes on this wrapper element before handing the reader to ReadObject.

Al utilizar una de las sobrecargas simples ReadObject , el deserializador busca el nombre y el espacio de nombres predeterminados en el elemento contenedor (consulte la sección anterior, "especificar el nombre de raíz y el espacio de nombres predeterminados") e inicia una excepción si encuentra un elemento desconocido Element.When using one of the simple ReadObject overloads, the deserializer looks for the default name and namespace on the wrapper element (see the preceding section, "Specifying the Default Root Name and Namespace") and throws an exception if it finds an unknown element. En el ejemplo anterior se espera el elemento contenedor <Person> .In the preceding example, the <Person> wrapper element is expected. Se llama al método IsStartObject para comprobar que el lector está ubicado en un elemento que se denomina como esperado.The IsStartObject method is called to verify that the reader is positioned on an element that is named as expected.

Hay una manera de deshabilitar esta comprobación de nombre del elemento contenedor; algunas sobrecargas del método ReadObject toman el parámetro booleano verifyObjectName, que está establecido de forma predeterminada en true .There is a way to disable this wrapper element name check; some overloads of the ReadObject method take the Boolean parameter verifyObjectName, which is set to true by default. Cuando se establece en false, se ignoran el nombre y el espacio de nombres del elemento contenedor.When set to false, the name and namespace of the wrapper element is ignored. Esto es útil para leer XML escrito mediante el mecanismo de serialización paso a paso descrito previamente.This is useful for reading XML that was written using the step-by-step serialization mechanism described previously.

Uso del NetDataContractSerializerUsing the NetDataContractSerializer

DataContractSerializer La principal diferencia entre NetDataContractSerializer y es que DataContractSerializer utiliza los nombres de contrato de datos, mientras que NetDataContractSerializer las salidas se completan .NET Framework nombre de ensamblado y tipo en el XML serializado.The primary difference between the DataContractSerializer and the NetDataContractSerializer is that the DataContractSerializer uses data contract names, whereas the NetDataContractSerializer outputs full .NET Framework assembly and type names in the serialized XML. Esto significa que se han de compartir exactamente los mismos tipos entre los extremos de serialización y deserialización.This means that the exact same types must be shared between the serialization and deserialization endpoints. Esto significa que el mecanismo de tipos conocidos no se requiere con el NetDataContractSerializer , porque siempre se conocen los tipos exactos que se van a deserializar.This means that the known types mechanism is not required with the NetDataContractSerializer because the exact types to be deserialized are always known.

Sin embargo, pueden producirse varios problemas:However, several problems can occur:

  • Seguridad.Security. Se carga cualquier tipo en el XML que se esté deserializando.Any type found in the XML being deserialized is loaded. Esto se puede explotar para forzar la carga de tipos malintencionados.This can be exploited to force the loading of malicious types. El uso del NetDataContractSerializer con datos que no son de confianza solo se debería realizar si se utiliza un Enlazador de Serialización (mediante el parámetro del constructor o la propiedad Binder ).Using the NetDataContractSerializer with untrusted data should be done only if a Serialization Binder is used (using the Binder property or constructor parameter). El enlazador solo permite cargar tipos seguros.The binder permits only safe types to be loaded. El mecanismo del enlazador es idéntico al que utilizan los tipos en el espacio de nombres de System.Runtime.Serialization .The Binder mechanism is identical to the one that types in the System.Runtime.Serialization namespace use.

  • Control de versionesVersioning. El uso de nombres de ensamblado y tipos completos en el XML restringe en gran medida el control de versión de los tipos.Using full type and assembly names in the XML severely restricts how types can be versioned. No se pueden cambiar lo siguientes elementos: nombres de tipos, espacios de nombres, nombres de ensamblados y versiones de ensamblados.The following cannot be changed: type names, namespaces, assembly names, and assembly versions. Establecer la propiedad AssemblyFormat o el parámetro de constructor en Simple en lugar del valor predeterminado de Full permite los cambios de versión de ensamblado, pero no para tipos de parámetros genéricos.Setting the AssemblyFormat property or constructor parameter to Simple instead of the default value of Full allows for assembly version changes, but not for generic parameter types.

  • Interoperabilidad.Interoperability. Dado que .NET Framework nombres de tipo y de ensamblado se incluyen en el XML, las plataformas distintas de la .NET Framework no pueden tener acceso a los datos resultantes.Because .NET Framework type and assembly names are included in the XML, platforms other than the .NET Framework cannot access the resulting data.

  • Rendimiento.Performance. Escribir los nombres del ensamblado y el tipo aumenta significativamente el tamaño del XML resultante.Writing out the type and assembly names significantly increases the size of the resulting XML.

Este mecanismo es similar a la BinaryFormatter serialización binaria o SOAP utilizada por .NET Framework remoto (concretamente, SoapFormattery).This mechanism is similar to binary or SOAP serialization used by .NET Framework remoting (specifically, the BinaryFormatter and the SoapFormatter).

El uso del NetDataContractSerializer es similar al uso del DataContractSerializer, con las siguientes diferencias:Using the NetDataContractSerializer is similar to using the DataContractSerializer, with the following differences:

  • Los constructores no le exigen que especifique un tipo de raíz.The constructors do not require you to specify a root type. Puede serializar cualquier tipo con la misma instancia del NetDataContractSerializer.You can serialize any type with the same instance of the NetDataContractSerializer.

  • Los constructores no aceptan ninguna lista de tipos conocidos.The constructors do not accept a list of known types. El mecanismo de tipos conocidos no es necesario si los nombres de tipos se serializan en el XML.The known types mechanism is unnecessary if type names are serialized into the XML.

  • Los constructores no aceptan un contrato de datos suplente.The constructors do not accept a data contract surrogate. En su lugar, aceptan un parámetro ISurrogateSelector llamado surrogateSelector (que asigna a la propiedad SurrogateSelector ).Instead, they accept an ISurrogateSelector parameter called surrogateSelector (which maps to the SurrogateSelector property). Éste es un mecanismo suplente de herencia.This is a legacy surrogate mechanism.

  • Los constructores aceptan un parámetro denominado assemblyFormat del FormatterAssemblyStyle que asigna a la propiedad AssemblyFormat .The constructors accept a parameter called assemblyFormat of the FormatterAssemblyStyle that maps to the AssemblyFormat property. Tal y como se comentó previamente, esto se puede utilizar para mejorar las capacidades del control de versiones del serializador.As discussed previously, this can be used to enhance the versioning capabilities of the serializer. Esto es idéntico al mecanismo FormatterAssemblyStyle en la serialización binaria o de SOAP.This is identical to the FormatterAssemblyStyle mechanism in binary or SOAP serialization.

  • Los constructores aceptan un parámetro StreamingContext denominado context que asigna a la propiedad Context .The constructors accept a StreamingContext parameter called context that maps to the Context property. Puede utilizar esto para pasar información en los tipos que se serializan.You can use this to pass information into types being serialized. Este uso es idéntico al del mecanismo StreamingContext utilizado en otras clases System.Runtime.Serialization .This usage is identical to that of the StreamingContext mechanism used in other System.Runtime.Serialization classes.

  • Los métodos Serialize y Deserialize son alias de los métodos WriteObject y ReadObject .The Serialize and Deserialize methods are aliases for the WriteObject and ReadObject methods. Éstos existen para proporcionar un modelo de programación con serialización binaria o de SOAP más coherente.These exist to provide a more consistent programming model with binary or SOAP serialization.

Para obtener más información sobre estas características, vea serialización binaria.For more information about these features, see Binary Serialization.

Generalmente, los formatos XML que usan el NetDataContractSerializer y el DataContractSerializer no son compatibles.The XML formats that the NetDataContractSerializer and the DataContractSerializer use are normally not compatible. Es decir, intentar serializar con uno de estos serializadores y deserializar con el otro no es un escenario admitido.That is, attempting to serialize with one of these serializers and deserialize with the other is not a supported scenario.

Además, tenga en cuenta NetDataContractSerializer que el no genera el tipo de .NET Framework completo y el nombre de ensamblado para cada nodo del gráfico de objetos.Also, note that the NetDataContractSerializer does not output the full .NET Framework type and assembly name for each node in the object graph. Solo genera esa información cuando hay ambigüedad.It outputs that information only where it is ambiguous. Es decir, produce el resultado en el nivel del objeto raíz y para cualquier caso polimórfico.That is, it outputs at the root object level and for any polymorphic cases.

Vea tambiénSee also