Freigeben über


Versionstolerante Serialisierung

In Version 1.0 und Version 1.1 von .NET Framework war das Erstellen serialisierbarer Typen, die für mehrere Anwendungsversionen verwendbar waren, problematisch. Wenn ein Typ durch Hinzufügen eines zusätzlicher Felder geändert wurde, traten die folgenden Probleme auf:

  • Ältere Versionen einer Anwendung lösten bei dem Versuch, neue Versionen des alten Typs zu deserialisieren, Ausnahmen aus.

  • Neuere Versionen einer Anwendung lösten bei dem Versuch, ältere Versionen eines Typs mit fehlenden Daten zu deserialisieren, Ausnahmen aus.

Bei VTS (Version Tolerant Serialization) handelt es sich um eine Gruppe von Funktionen, die in .NET Framework 2.0 eingeführt wurde, um das möglicherweise im Laufe der Zeit erforderliche Ändern serialisierbarer Typen zu vereinfachen. Die VTS-Funktionen sind insbesondere für Klassen aktiviert, auf die das SerializableAttribute-Attribut angewendet wurde, einschließlich generischer Typen. VTS ermöglicht das Hinzufügen neuer Felder zu diesen Klassen, ohne die Kompatibilität mit anderen Versionen des Typs zu beeinträchtigen. Eine funktionierende Beispielanwendung finden Sie unter Technologiebeispiel für versionstolerante Serialisierung.

Die VTS-Funktionen werden bei der Verwendung von BinaryFormatter aktiviert. Zudem sind alle Funktionen mit Ausnahme der Toleranz für externe Daten auch bei der Verwendung von SoapFormatter aktiviert. Weitere Informationen zur Verwendung dieser Klassen für die Serialisierung finden Sie unter Binäre Serialisierung.

Funktionsliste

VTS umfasst die folgenden Funktionen:

  • Toleranz für externe oder unerwartete Daten. Dies ermöglicht es neueren Versionen des Typs, Daten an frühere Versionen zu senden.

  • Toleranz für fehlende optionale Daten. Dies ermöglicht es älteren Versionen, Daten an neuere Versionen zu senden.

  • Serialisierungsrückrufe. Dies ermöglicht ein intelligentes Festlegen von Standardwerten im Fall fehlender Daten.

Zudem ist eine Funktion zum Deklarieren verfügbar, wenn ein neues optionales Feld hinzugefügt wurde. Es handelt sich hierbei um die VersionAdded-Eigenschaft des OptionalFieldAttribute-Attributs.

Diese Funktionen werden nachfolgend näher erläutert.

Toleranz für externe oder unerwartete Daten

In früheren Versionen wurden während der Deserialisierung bei auftretenden externen oder unerwarteten Daten Ausnahmen. Mit VTS werden in derselben Situation keine Ausnahmen mehr ausgelöst, sondern alle externen oder unerwarteten Daten werden ignoriert. Dies ermöglicht es, Anwendungen mit neueren Versionen eines Typs (d. h. eine Version mit mehr Feldern), Informationen an Anwendungen zu senden, die ältere Versionen desselben Typs erwarten.

Im folgenden Beispiel werden die zusätzlichen Daten im CountryField-Feld von Version 2.0 der Address-Klasse ignoriert, wenn eine ältere Anwendung die neuere Version deserialisiert.

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

Toleranz für fehlende Daten

Felder können mithilfe des OptionalFieldAttribute-Attributs als optional markiert werden. Wenn während der Deserialisierung optionale Daten fehlen, ignoriert das Serialisierungsmodul das Fehlen dieser Daten und löst keine Ausnahme aus. Anwendungen, die ältere Versionen eines Typs erwarten, können daher Daten an Anwendungen senden, die neuere Versionen desselben Typs erwarten.

Im folgenden Beispiel wird Version 2.0 der Address-Klasse mit dem als optional markierten CountryField-Feld veranschaulicht. Wenn eine ältere Anwendung Version 1 an eine neuere Anwendung sendet, die Version 2.0 erwartet, wird das Fehlen der Daten ignoriert.

[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

Serialisierungsrückrufe

Serialisierungsrückrufe stellen einen Mechanismus dar, der an vier Punkten im Serialisierungs-/Deserialisierungsprozess Hooks bereitstellt.

Attribut Beim Aufruf der verknüpften Methode Typische Verwendung

OnDeserializingAttribute

Vor der Deserialisierung. *

Initialisieren von Standardwerten für optionale Felder.

OnDeserializedAttribute

Nach der Deserialisierung.

Korrigieren Sie optionale Feldwerte auf der Grundlage des Inhalts anderer Felder.

OnSerializingAttribute

Vor der Deserialisierung.

Vorbereiten der Serialisierung. Erstellen Sie z. B. optionale Datenstrukturen.

OnSerializedAttribute

Nach der Serialisierung.

Protokollieren der Serialisierungsereignisse.

* Dieser Rückruf wird vor dem Deserialisierungskonstruktor aufgerufen, sofern ein solcher vorhanden ist.

Verwenden von Rückrufen

Zur Verwendung von Rückrufen wenden Sie die entsprechenden Attribute auf eine Methode an, die einen StreamingContext-Parameter akzeptiert. Mit jedem dieser Attribute kann nur eine Methode pro Klasse markiert werden. Beispiel:

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

Diese Methoden sind für die Versionsverwaltung vorgesehen. Während der Deserialisierung wird ein optionales Feld möglicherweise nicht korrekt initialisiert, wenn die Daten für das Feld fehlen. Dies kann korrigiert werden, indem zunächst die Methode erstellt wird, die den richtigen Wert zuordnet, und dann entweder das OnDeserializingAttribute-Attribut oder das OnDeserializedAttribute-Attribut auf die Methode anwendet wird.

Im folgenden Beispiel wird die Methode im Kontext eines Typs veranschaulicht. Wenn eine frühere Version einer Anwendung eine Instanz derAddress-Klasse an eine höhere Version der Anwendung sendet, fehlen Daten im CountryField-Feld. Nach der Deserialisierung wird für das Feld jedoch der Standardwert "Japan" festgelegt.

[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

Die VersionAdded-Eigenschaft

Das OptionalFieldAttribute-Objekt verfügt über die VersionAdded-Eigenschaft. In Version 2.0 von .NET Framework wird diese nicht verwendet. Es ist jedoch wichtig, dass diese Eigenschaft richtig festgelegt wird, um sicherzustellen, dass der Typ mit zukünftigen Serialisierungmodulen kompatibel ist.

Die Eigenschaft gibt an, welche Version eines Typs einem bestimmten Feld hinzugefügt wurde. Sie sollte bei jeder Änderung des Typs um genau 1 erhöht werden (ausgehend von 2). Dies veranschaulicht das folgende Beispiel:

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

Einige Benutzer müssen möglicherweise steuern, welche Klasse serialisiert und deserialisiert werden soll, da eine andere Version der Klasse auf dem Server und Client erforderlich ist. SerializationBinder ist eine abstrakte Klasse, mit der die tatsächlich während der Serialisierung und Deserialisierung verwendeten Typen gesteuert werden. Wenn Sie diese Klasse verwenden möchten, müssen Sie eine Klasse von SerializationBinder ableiten und die BindToName-Methode und die BindToType überschreiben. siehe Controlling Serialization and Deserialization with SerializationBinder.

Bewährte Vorgehensweisen

Um das richtige Versionsverhalten sicherzustellen, beachten Sie beim Ändern eines Typs von Version zu Version die folgenden Regeln:

  • Entfernen Sie nie ein serialisiertes Feld.

  • Wenden Sie das NonSerializedAttribute-Attribut nie auf ein Feld an, wenn das Attribut in der vorherigen Version nicht auf das Feld angewendet wurde.

  • Ändern Sie nie den Namen oder den Typ eines serialisierten Felds.

  • Wenden Sie beim Hinzufügen eines neuen serialisierten Felds das OptionalFieldAttribute-Attribut an.

  • Wenden Sie beim Entfernen eines NonSerializedAttribute-Attributs von einem Feld, das in einer vorherigen Version nicht serialisierbar war, das OptionalFieldAttribute-Attribut an.

  • Legen Sie für alle optionalen Felder sinnvolle Standardwerte fest, indem Sie die Serialisierungsrückrufe verwenden, sofern 0 oder nullnicht als Standardwerte zulässig sind.

Um sicherzustellen, dass ein Typ mit zukünftigen Serialisierungsmodulen kompatibel ist, beachten Sie die folgenden Richtlinien:

  • Legen Sie die VersionAdded-Eigenschaft für das OptionalFieldAttribute-Attribut immer richtig fest.

  • Vermeiden Sie verzweigte Versionen.

Siehe auch

Verweis

SerializableAttribute
BinaryFormatter
SoapFormatter
VersionAdded
OptionalFieldAttribute
OnDeserializingAttribute
OnDeserializedAttribute
OnDeserializingAttribute
OnSerializedAttribute
StreamingContext
NonSerializedAttribute

Weitere Ressourcen

Binäre Serialisierung