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.
Hinweis |
|---|
| 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.
// 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.
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.
[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
|
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:
[OnDeserializing]
private void SetCountryRegionDefault(StreamingContext sc)
{
CountryField = "Japan";
}
[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.
[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
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
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:
Siehe auch