Compartir a través de


Serialización tolerante a versiones

En la versión 1.0 y 1.1 de .NET Framework, la creación de tipos serializables que serían reutilizables a partir de una versión de una aplicación a lo siguiente, ha resultado problemática. Si un tipo se modificara agregando los campos adicionales, se producirían los problemas siguientes:

  • Las versiones anteriores de una aplicación produciría excepciones en caso de solicitar la deserialización de las nuevas versiones del tipo anterior.

  • Las versiones más recientes de una aplicación producirían las excepciones al deserializar versiones anteriores de un tipo con datos que faltan.

La Serialización Tolerante a versiones (VTS) es un conjunto de características introducido en .NET Framework 2.0 que facilita, con el tiempo, modificar los tipos serializables. Específicamente, las características VTS están habilitadas para las clases a las que se ha aplicado el atributo SerializableAttribute, incluidos los tipos genéricos. VTS posibilita el agregar los nuevos campos a esas clases sin interrumpir la compatibilidad con otras versiones del tipo. Para obtener una aplicación de ejemplo de trabajo, vea Ejemplo de Version Tolerant Serialization Technology.

Las características VTS están habilitadas al utilizar BinaryFormatter. Además, todas las características, excepto la tolerancia de datos extraños, están habilitadas también al utilizar SoapFormatter. Para obtener más información sobre la utilización de estas clases para la serialización, vea Serialización binaria.

Lista de características

En la lista de características se incluyen las siguientes:

  • Tolerancia de datos extraños o inesperados. Esto permite a las versiones más recientes del tipo enviar los datos a las versiones anteriores.

  • Tolerancia de datos opcionales que faltan. Esto permite a las versiones anteriores enviar los datos a las versiones más recientes.

  • Devoluciones de llamada de la serialización. Esto habilita el valor predeterminado inteligente en casos donde faltan datos.

Hay además, una característica para declarar cuando se ha agregado un nuevo campo opcional. Ésta es la propiedad VersionAdded del atributo OptionalFieldAttribute.

Estas características se discuten abajo en detalle.

Tolerancia de datos extraños o inesperados.

En el pasado, durante la deserialización, cualquier dato extraño o inesperado produjeron excepciones. Con VTS, en la misma situación, cualquier dato extraño o inesperado se omite en lugar de producir excepciones. Esto habilita aplicaciones que utilizan versiones más recientes de un tipo (es decir, una versión que incluye más campos) para enviar información a las aplicaciones que esperan versiones anteriores del mismo tipo.

En el ejemplo siguiente, los datos adicionales contenidos en CountryField de la versión 2.0 de la clase Address se omiten cuando una aplicación anterior deserializa la versión más reciente.

// Version 1 of the Address class.
[Serializable]
public class Address
{
    public string Street;
    public string City;
}
// Version 2.0 of the Address class.
[Serializable]
public class Address
{
    public string Street;
    public string City;
    // The older application ignores this data.
    public string CountryField;
}
' Version 1 of the Address class.
<Serializable> _
Public Class Address
    Public Street As String
    Public City As String
End Class

' Version 2.0 of the Address class.
<Serializable> _
Public Class Address
    Public Street As String
    Public City As String
    ' The older application ignores this data.
    Public CountryField As String
End Class

Tolerancia de datos que faltan.

Los campos se pueden marcar como opcionales aplicando el atributo OptionalFieldAttribute a ellos. Durante la deserialización, si faltan datos opcionales, el motor de la serialización omite la ausencia y no inicia una excepción. Así, las aplicaciones que esperan versiones anteriores de un tipo pueden enviar los datos a las aplicaciones que esperan versiones más recientes del mismo tipo.

El ejemplo siguiente muestra la versión 2.0 de la clase Address con el campo CountryField marcado como opcional. Si una aplicación más anterior envía la versión 1 a una aplicación más reciente que espera la versión 2.0, se omite la ausencia de los datos.

[Serializable]
public class Address
{
    public string Street;
    public string City;

    [OptionalField]
    public string CountryField;
}
<Serializable> _
Public Class Address
    Public Street As String
    Public City As String

    <OptionalField> _
    Public CountryField As String
End Class

Devoluciones de llamada de la serialización

Las devoluciones de llamada de la serialización son un mecanismo que proporciona los enlaces en el proceso de serialización/deserialización en cuatro puntos.

Atributo Cuando se llama al método asociado. Uso típico

OnDeserializingAttribute

Antes de la deserialización. *

Inicialice los valores predeterminados para los campos opcionales.

OnDeserializedAttribute

Después de la deserialización.

Corrija valores de campo opcionales basados en el contenido de otros campos.

OnSerializingAttribute

Antes de la serialización. *

Prepare para la serialización. Por ejemplo, cree las estructuras de datos opcionales.

OnSerializedAttribute

Después de la serialización.

Registre los eventos de serialización.

* Esta devolución de llamada se invoca antes del constructor de deserialización, si uno está presente.

Utilizar las devoluciones de llamada

Para utilizar las devoluciones de llamada, aplique el atributo adecuado a un método que acepta un parámetro StreamingContext. Solo se puede marcar un método por clase con cada uno de estos atributos. Por ejemplo:

[OnDeserializing]
private void SetCountryRegionDefault(StreamingContext sc)
{
    CountryField = "Japan";
}
<OnDeserializing>
Private Sub SetCountryRegionDefault(StreamingContext sc)
    CountryField = "Japan";
End Sub

El uso previsto de estos métodos es para las versiones. Durante la deserialización, un campo opcional no se puede inicializar correctamente si faltan los datos para el campo. Esto se puede corregir creando el método que asigna el valor correcto, aplicando a continuación OnDeserializingAttribute o el atributo OnDeserializedAttribute al método.

El ejemplo siguiente muestra el método en el contexto de un tipo. Si una versión anterior de una aplicación envía una instancia de la clase Address a una versión posterior de la aplicación, faltarán los datos de campo CountryField. Pero después de la deserialización, el campo estará establecido con el valor predeterminado "Japan".

[Serializable]
public class Address
{
    public string Street;
    public string City;
    [OptionalField]
    public string CountryField;

    [OnDeserializing]
    private void SetCountryRegionDefault (StreamingContext sc)
    {
        CountryField = "Japan";
    }
}
<Serializable> _
Public Class Address
    Public Street As String
    Public City As String
    <OptionalField> _
    Public CountryField As String

    <OnDeserializing> _
    Private Sub SetCountryRegionDefault(StreamingContext sc)
        CountryField = "Japan";
    End Sub
End Class

La propiedad VersionAdded

La OptionalFieldAttribute tiene la propiedad VersionAdded. Esto no se utiliza en la versión 2.0 de .NET Framework. Sin embargo, es importante para establecer correctamente esta propiedad asegurarse de que el tipo será compatible con motores de la serialización futuros.

La propiedad indica qué versión de un tipo de un campo determinado se ha agregado. Se debería incrementar en uno exactamente (comenzando en 2) cada vez que se modifica el tipo, como se muestra en el ejemplo siguiente:

// Version 1.0
[Serializable]
public class Person
{
    public string FullName;
}

// Version 2.0
[Serializable]
public class Person
{
    public string FullName;

    [OptionalField(VersionAdded = 2)]
    public string NickName;
    [OptionalField(VersionAdded = 2)]
    public DateTime BirthDate;
}

// Version 3.0
[Serializable]
public class Person
{
    public string FullName;

    [OptionalField(VersionAdded=2)]
    public string NickName;
    [OptionalField(VersionAdded=2)]
    public DateTime BirthDate;

    [OptionalField(VersionAdded=3)]
    public int Weight;
}
' Version 1.0
<Serializable> _
Public Class Person
    Public FullName
End Class

' Version 2.0
<Serializable> _
Public Class Person
    Public FullName As String

    <OptionalField(VersionAdded := 2)> _
    Public NickName As String
    <OptionalField(VersionAdded := 2)> _
    Public BirthDate As DateTime
End Class

' Version 3.0
<Serializable> _
Public Class Person
    Public FullName As String

    <OptionalField(VersionAdded := 2)> _
    Public NickName As String
    <OptionalField(VersionAdded := 2)> _
    Public BirthDate As DateTime

    <OptionalField(VersionAdded := 3)> _
    Public Weight As Integer
End Class

SerializationBinder

Algunos usuarios pueden necesitar controlar la clase que se serializará y deserializará porque se necesita una versión diferente de la clase en el servidor y cliente. SerializationBinder es una clase abstracta utilizada para controlar los tipos reales utilizados durante la serialización y deserialización. Para usar esta clase, obtenga una clase de SerializationBinder y omita los métodos BindToName y BindToType. , vea Controlling Serialization and Deserialization with SerializationBinder.

Procedimientos recomendados

Para asegurar el comportamiento apropiado de la versión, siga estas reglas al modificar un tipo de la versión para la versión:

  • Nunca quite un campo serializado.

  • Nunca aplique el atributo NonSerializedAttribute a un campo si el atributo no se aplicó al campo en la versión anterior.

  • Nunca cambie el nombre o el tipo de un campo serializado.

  • Al agregar un nuevo campo serializado, aplique el atributo OptionalFieldAttribute.

  • Al quitar un atributo NonSerializedAttribute de un campo (que no fue serializable en una versión anterior), aplique el atributo OptionalFieldAttribute.

  • Para todos los campos opcionales, establezca los valores predeterminados significativos utilizando las devoluciones de llamada de la serialización menores que 0 o nullcuando los valores predeterminados son aceptables.

Para asegurarse de que un tipo será compatible con motores de serialización futuros, siga estas instrucciones:

  • Establezca correctamente siempre la propiedad VersionAdded en el atributo OptionalFieldAttribute.

  • Evite la versión bifurcada.

Vea también

Referencia

SerializableAttribute
BinaryFormatter
SoapFormatter
VersionAdded
OptionalFieldAttribute
OnDeserializingAttribute
OnDeserializedAttribute
OnDeserializingAttribute
OnSerializedAttribute
StreamingContext
NonSerializedAttribute

Otros recursos

Serialización binaria