Binary Formatter

Please note: This article is only available in German.
Der eingebaute BinaryFormatter tut Objekte samt deren Namensraum serialisieren, was beim Ändern des Namespaces für Probleme sorgt

Der BinaryFormatter ist ein sehr nützliches Objekt wenn es um die Binäre Serialisierung und Deserialisierung von Klasseninstanzen geht. Beim Wechseln des Namespaces der serialisierten Klasse läßt sich diese jedoch nicht mehr deserialisieren.

Grundlegende Verwendung des BinaryFormatters

Um ein Byte-Array (bzw. einen Stream von Bytes) in ein entsprechendes Objekt bzw. eine Objektinstanz zu verwandeln brauchen wir nur den BinaryFormatter instanziieren und auf einen Stream (z.B. einen MemoryStream) anwenden.

private static object ByteArrayToObject(byte[] Buffer)
{
  BinaryFormatter formatter = new BinaryFormatter();
  MemoryStream stream = new MemoryStream(Buffer);
  try 
  { return formatter.Deserialize(stream); }
  catch
  { return null; }
}

Die Serialisierung erfolgt ganz analog, nur dass wir hier die konkrete Objektinstanz übergeben und am Ende ein Byte-Array erhalten.

private static byte[] ObjectToByteArray(object obj)
{
  MemoryStream fs = new MemoryStream();
  BinaryFormatter formatter = new BinaryFormatter();
  try
  {
    formatter.Serialize(fs, obj);
    return fs.ToArray();
  }
  catch
  { return new byte[0]; }
  finally 
  { fs.Close(); }
}

Haben wir eine Instanz bereits Serialisiert und wollen diese wieder Deserialisieren, so stellt dies kein Problem dar solange wir nicht den Namespace der Klassendefinition ändern. Nach dem Ändern des Namensraums stellen wir zu unserem Entsetzen fest, dass wir folgende Fehlermeldung erhalten: The ObjectManager found an invalid number of fixups. This is usually indicates a problem in the formatter.

Lösung des Problems

Die Lösung des Problems läuft über eine spezialisierte Version der Klasse SerializationBinder. Um die spezialisierte Instanz einer solchen Klasse einzubinden nutzen wir die Eigenschaft Binder der BinaryFormatter Instanz. Da wir dieses Problem nur beim Deserialisieren erhalten, müssen wir die Änderung auch nur für unsere ByteArrayToObject-Methode implementieren.

Der Code für unsere spezialisierte SerializationBinder Klasse lautet:

class Binder : SerializationBinder
{
  public override Type BindToType(string assemblyName, string typeName)
  {
    typeName = typeName.Replace("Vorheriger Namensraum", "Neuer Namensraum");
    return Type.GetType(typeName);
  }
}

In unserer ByteArrayToObject-Methode fügen wir nun noch die Änderung ein um somit folgenden Methodenkörper zu erhalten:

BinaryFormatter formatter = new BinaryFormatter();
formatter.Binder = new Binder();
//Rest wie gehabt mit MemoryStream usw.

Nun funktioniert das Deserialisieren wieder wie gewohnt.

Created . Last updated .

References

Sharing is caring!