Partager via


Sérialisation avec tolérance de version

Dans les versions 1.0 et 1.1 du .NET Framework, la création de types sérialisables pouvant être réutilisés d'une version d'application à l'autre était problématique. Si un type était modifié via l'ajout de champs supplémentaires, les problèmes suivants étaient susceptibles de se produire :

  • Les versions antérieures d'une application pouvaient lever des exceptions lorsque l'utilisateur tentait de désérialiser les nouvelles versions du type précédent.

  • Les versions plus récentes d'une application pouvaient lever des exceptions lors de la désérialisation de versions antérieures d'un type ayant des données manquantes.

La Sérialisation avec tolérance de version (VTS) comprend un ensemble de fonctionnalités introduites dans .NET Framework 2.0 et qui simplifient, au fil du temps, la modification des types sérialisables. Plus précisément, les fonctions VTS sont activées pour les classes auxquelles l'attribut SerializableAttribute a été appliqué, y compris des types génériques. VTS permet d'ajouter de nouveaux champs à ces classes en assurant la compatibilité avec d'autres versions du type. Pour obtenir un exemple d'application fonctionnel, consultez Sérialisation avec tolérance de version, exemple de technologie.

Les fonctions VTS sont activées lors de l'utilisation de BinaryFormatter. En outre, toutes les fonctionnalités, hormis la tolérance de données étrangères, sont également activées lors de l'utilisation de SoapFormatter. Pour plus d'informations sur l'utilisation de ces classes en vue de la sérialisation, consultez Sérialisation binaire.

Liste des fonctionnalités

Cette liste comprend les fonctionnalités suivantes :

  • Tolérance de données étrangères ou inattendues. Cette fonctionnalité permet aux versions plus récentes du type d'envoyer des données aux versions antérieures.

  • Tolérance de données facultatives manquantes. Cette fonctionnalité permet aux versions antérieures d'envoyer des données aux versions plus récentes.

  • Rappels de sérialisation. Cette fonctionnalité active le paramètre de valeur par défaut intelligent en cas de données manquantes.

Une fonctionnalité permet en outre de générer une déclaration lors de l'ajout d'un nouveau champ facultatif. Il s'agit de la propriété VersionAdded de l'attribut OptionalFieldAttribute.

Ces fonctionnalités sont abordées de manière plus détaillée ci-dessous.

Tolérance de données étrangères ou inattendues

Auparavant, lors de la désérialisation, toute donnée étrangère ou inattendue entraînait la levée d'exceptions. Avec VTS, dans la même situation, toutes les données étrangères ou inattendues sont ignorées au lieu de provoquer la levée d'exceptions. Cela permet aux applications qui utilisent des versions plus récentes d'un type (autrement dit, une version qui inclut plus de champs) d'envoyer des informations aux applications qui nécessitent des versions antérieures du même type.

Dans l'exemple suivant, les données supplémentaires contenues dans le champ CountryField de la version 2.0 de la classe Address sont ignorées lorsqu'une application plus ancienne désérialise la version plus récente.

// 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

Tolérance de données manquantes

Les champs peuvent être marqués comme facultatifs en leur appliquant l'attribut OptionalFieldAttribute. Lors de la désérialisation, si des données facultatives sont manquantes, le moteur de sérialisation ignore leur absence et ne lève aucune exception. Les applications qui nécessitent des versions antérieures d'un type peuvent ainsi envoyer des données aux applications qui nécessitent des versions plus récentes du même type.

L'exemple suivant illustre la version 2.0 de la classe Address, avec le champ CountryField marqué comme facultatif. Si une application plus ancienne envoie la version 1 à une application plus récente qui nécessite la version 2.0, l'absence des données est ignorée.

[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

Rappels de sérialisation

Les rappels de sérialisation correspondent à un mécanisme qui fournit des raccordements lors du processus de sérialisation/désérialisation au niveau de quatre points.

Attribut Lorsque la méthode associée est appelée Utilisation courante

OnDeserializingAttribute

Avant la désérialisation.*

Initialisez des valeurs par défaut pour les champs facultatifs.

OnDeserializedAttribute

Après la désérialisation.

Corrigez des valeurs de champ facultatives selon le contenu d'autres champs.

OnSerializingAttribute

Avant la sérialisation.

Préparez la sérialisation. Par exemple, créez des structures de données facultatives.

OnSerializedAttribute

Après la sérialisation.

Enregistrez des événements de sérialisation.

* Ce rappel est appelé avant le constructeur de désérialisation, le cas échéant.

Utilisation de rappels

Pour utiliser des rappels, appliquez l'attribut approprié à une méthode qui accepte un paramètre StreamingContext. Une seule méthode par classe peut être marquée avec chacun de ces attributs. Par exemple :

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

Ces méthodes sont destinées à être utilisées pour le versioning. Pendant la désérialisation, un champ facultatif ne peut pas être initialisé correctement si les données du champ sont manquantes. Cela peut être corrigé en créant la méthode qui assigne la valeur correcte, puis en appliquant l'attribut OnDeserializingAttribute ou OnDeserializedAttribute à la méthode.

L'exemple suivant illustre la méthode dans le cadre d'un type. Si une version antérieure d'une application envoie une instance de la classe Address à une version ultérieure de l'application, les données du champ CountryField sont omises. Mais après la désérialisation, le champ aura pour valeur la valeur par défaut « 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

Propriété VersionAdded

OptionalFieldAttribute a la propriété VersionAdded. Dans la version 2.0 du .NET Framework, celle-ci n'est pas utilisée. Toutefois, il est important de définir correctement cette propriété pour garantir que le type soit compatible avec les futurs moteurs de sérialisation.

La propriété indique quelle version d'un type a été ajoutée à un champ donné. Elle doit être incrémentée d'une seule valeur (à partir de 2) à chaque fois que le type est modifié, comme illustré dans l'exemple suivant :

// 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

Il est possible que certains utilisateurs soient tenus de contrôler la classe à sérialiser et à désérialiser si une version différente de la classe est requise sur le serveur et le client. SerializationBinder est une classe abstraite prévue pour contrôler les types réels utilisés au cours de la sérialisation et de la désérialisation. Pour tirer parti de cette classe, dérivez une classe de SerializationBinder et substituez une méthode aux deux suivantes : BindToName et BindToType. Pour , voir Controlling Serialization and Deserialization with SerializationBinder.

Méthodes conseillées

Pour garantir un comportement de versioning correct, suivez les règles ci-dessous lors de la modification d'un type d'une version à l'autre :

  • Ne supprimez jamais un champ sérialisé.

  • N'appliquez jamais l'attribut NonSerializedAttribute à un champ si cet attribut n'a pas été appliqué au champ dans la version antérieure.

  • Ne modifiez jamais le nom ou le type d'un champ sérialisé.

  • Lorsque vous ajoutez un nouveau champ sérialisé, appliquez l'attribut OptionalFieldAttribute.

  • Lorsque vous supprimez un attribut NonSerializedAttribute d'un champ (qui n'était pas sérialisable dans une version antérieure), appliquez l'attribut OptionalFieldAttribute.

  • Affectez des valeurs par défaut significatives à tous les champs facultatifs à l'aide des rappels de sérialisation, tant que les valeurs par défaut 0 ou Null sont acceptables.

Pour garantir la compatibilité d'un type avec les futurs moteurs de sérialisation, suivez ces indications :

  • Affectez toujours correctement la propriété VersionAdded à l'attribut OptionalFieldAttribute.

  • Évitez le versioning avec des branches.

Voir aussi

Référence

SerializableAttribute
BinaryFormatter
SoapFormatter
VersionAdded
OptionalFieldAttribute
OnDeserializingAttribute
OnDeserializedAttribute
OnDeserializingAttribute
OnSerializedAttribute
StreamingContext
NonSerializedAttribute

Autres ressources

Sérialisation binaire