Versionstolerante Serialisierung

In Version 1.0 und Version 1.1 von .NET Framework war das Erstellen serialisierbarer Typen, die von einer Anwendungsversion zur nächsten wiederverwendbar waren, problematisch. Wenn ein Typ durch Hinzufügen eines zusätzlichen Felds geändert wurde, trat das folgende Problem 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 Features, 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-Features sind für Klassen aktiviert, auf die das SerializableAttribute-Attribut angewendet wurde. VTS ermöglicht das Hinzufügen neuer Felder zu diesen Klassen, ohne die Kompatibilität mit anderen Versionen des Typs zu beeinträchtigen. Eine funktionsfähige Beispielanwendung finden Sie unter Version Tolerant Serialization Technology Sample.

Die VTS-Features sind bei der Verwendung von BinaryFormatter aktiviert. Zudem sind alle Features 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.

NoteHinweis

Das Feature Toleranz für externe Daten für BinaryFormatter wird möglicherweise für .NET Framework 1.1 als Patch oder zu einem späteren Zeitpunkt verfügbar sein.

Featureliste

VTS umfasst die folgenden Features:

  • Toleranz für externe oder unerwartete Daten. Dies ermöglicht neueren Versionen des Typs das Senden von Daten an ältere Versionen.

  • Toleranz für fehlende optionale Daten. Dies ermöglicht älteren Versionen das Senden von Daten an neuere Versionen.

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

Zusätzlich gibt es ein Feature zum Deklarieren, wenn ein neues optionales Feld hinzugefügt wurde. Dies ist die VersionAdded-Eigenschaft des OptionalFieldAttribute-Attributs.

Diese Features werden nachfolgend näher beschrieben.

Toleranz für externe oder unerwartete Daten

In früheren Versionen wurden während der Deserialisierung bei auftretenden externen oder unerwarteten Daten Ausnahmen ausgelöst. 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 in CountryField von Version 2.0 der Address-Klasse ignoriert, wenn eine ältere Anwendung die neuere Version deserialisiert.

C#
// 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;
}
Visual Basic
' 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.

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

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

    [OptionalField]
    public string CountryField;
}
Visual Basic
<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 Bei Aufruf der verknüpften Methode Typische Verwendung

OnDeserializingAttribute

Vor der Deserialisierung.*

Initialisieren von Standardwerten für optionale Felder.

OnDeserializedAttribute

Nach der Deserialisierung.*

Korrigieren optionaler Feldwerte basierend auf dem Inhalt anderer Felder.

OnSerializingAttribute

Vor der Serialisierung.

Vorbereiten der Serialisierung. Zum Beispiel das Erstellen optionaler Datenstrukturen.

OnSerializedAttribute

Nach der Serialisierung.

Protokollieren der Serialisierungsereignisse.

* Dieser Rückruf wird vor Auftreten des Deserialisierungskonstruktors (falls vorhanden) ausgelöst.

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:

C#
[OnDeserializing]
private void SetCountryRegionDefault(StreamingContext sc)
{
    CountryField = "Japan";
}
Visual Basic
[OnDeserializing]
private void SetCountryRegionDefault(StreamingContext sc)
{
    CountryField = "Japan";
}

Die Verwendung dieser Methoden ist für die Versionsverwaltung vorgesehen. Während der Deserialisierung ist ein optionales Feld möglicherweise nicht korrekt initialisiert, wenn die Daten für das Feld fehlen. Dies kann berichtigt 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 angewendet wird.

Das folgende Beispiel veranschaulicht die Methode im Kontext eines Typs. Wenn eine frühere Version einer Anwendung eine Instanz der Address-Klasse an eine höhere Version der Anwendung sendet, fehlen Daten im CountryField-Feld. Nach der Deserialisierung wird das Feld jedoch auf den Standardwert Japan festgelegt.

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

    [OnDeserializing]
    private void SetCountryRegionDefault (StreamingContext sc)
    {
        CountryField = "Japan";
    }
}
Visual Basic
<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

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:

C#
// 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;
}
Visual Basic
' 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

Empfohlene Vorgehensweisen

Um ein richtiges 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 null nicht 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

Page view tracker