1. Einleitung
In vielen alten Lehrbüchern und Beispielen zu C# findet man Serialisierung mit der Klasse BinaryFormatter. Früher war das Standard: praktisch, schnell, weniger Aufwand. Ein Beispiel aus alten Zeiten sah ungefähr so aus:
// Gefährlicher alter Code! Nicht so in neuen Projekten verwenden!
var bf = new BinaryFormatter();
using (var stream = File.Open("player.dat", FileMode.Create))
{
bf.Serialize(stream, playerObject);
}
In modernem .NET 9 könnt ihr solchen Code nicht mal mehr kompilieren: BinaryFormatter wurde aus der Plattform entfernt.
Vom Helden zum Ausgestoßenen
Ursprünglich war BinaryFormatter als universeller Mechanismus zur Serialisierung und Deserialisierung von .NET‑Objekten gedacht, der komplexe Objektgraphen „wie sie sind“ speichern kann. Mit der Zeit traten jedoch gravierende Sicherheits‑ und Kompatibilitätsprobleme zutage, und inzwischen gehört er der Vergangenheit an — ungefähr wie Kassettenrekorder in der Streaming‑Ära.
2. Hauptgründe für die Abkehr von BinaryFormatter
Riesiges Sicherheitsloch
BinaryFormatter kann nicht nur Daten serialisieren, sondern auch Typen aus dem Eingabestrom rekonstruieren. Wenn man unüberlegte Deserialisierung von nicht vertrauenswürdigen Daten macht (z. B. aus dem Netzwerk), kann ein Angreifer eine Nutzlast einschleusen, die zur Remote‑Code‑Ausführung (RCE) führt. Genau deshalb hat Microsoft über viele Jahre gewarnt: „Verwendet nicht BinaryFormatter“. Ab .NET 5 wurde es als veraltet und gefährlich markiert ([Obsolete]), und in .NET 9 wurde es entfernt.
Abhängigkeit von der internen Klassenstruktur
Das Format von BinaryFormatter zieht Implementierungsdetails der Typen nach sich: Felder, Packing, Versionen. Kleinste Änderungen in Klassen (Feld hinzugefügt/entfernt) brechen die Kompatibilität mit bereits gespeicherten Dateien. Das macht das Format ungeeignet für langfristige Speicherung und versionsübergreifenden Austausch.
Probleme mit Cross‑Plattform
Daten, die mit BinaryFormatter gespeichert wurden, sind an die interne Repräsentation von .NET‑Objekten gebunden. Sie auf einer anderen Plattform/Sprache oder sogar in einer anderen .NET‑Version zu lesen ist oft unmöglich.
3. Wie man alten Code findet und was zu tun ist
Anzeichen für die Nutzung von BinaryFormatter sehen so aus:
using System.Runtime.Serialization.Formatters.Binary; // <-- verdächtig!
BinaryFormatter bf = new BinaryFormatter(); // <-- gefährlich!
bf.Serialize(...);
bf.Deserialize(...);
In modernen .NET‑Versionen kompiliert solcher Code nicht: die Tools melden einen Fehler wie "Typ oder Name nicht gefunden". In Legacy‑Projekten unter .NET Framework gibt es mindestens strenge Warnungen.
Wenn ihr auf solchen Code stoßt, ersetzt BinaryFormatter durch moderne, sichere Alternativen.
Welche Formate und Klassen heute verwenden?
Für JSON
- System.Text.Json — schnell, sicher, in .NET eingebaut. Offizielle Dokumentation
- Newtonsoft.Json — beliebte Drittanbieter‑Bibliothek für komplexe Fälle.
Für XML
- XmlSerializer — Serialisierung nach XML. Dokumentation
Für binäre Formate
- System.Formats.Cbor (CBOR)
- Protobuf.Net (Protocol Buffers), MessagePack for C#
Für spezifische Aufgaben wählt man spezialisierte Formate und Bibliotheken — einen „universellen“ binären Serializer im Stil von BinaryFormatter gibt es nicht mehr, und das ist gut so.
4. Code neu schreiben statt BinaryFormatter
Wofür man BinaryFormatter nicht verwenden darf
Nicht verwenden:
- Benutzereinstellungen und wichtige Daten speichern.
- Daten über das Netzwerk senden (Client ↔ Server).
- Daten aus nicht verifizierten Quellen deserialisieren.
Stattdessen:
- Für den Alltag — System.Text.Json.
- Für Konfigurationen — JSON, XML usw.
- Für sprachübergreifenden Austausch — Formate mit plattformübergreifender Kompatibilität (JSON, XML, Protobuf, MessagePack).
Welche Art von Code jetzt schreiben?
JSON‑Serialisierung (empfohlener Weg)
using System.Text.Json;
// Ihr Klasse:
public class Player
{
public string Name { get; set; } = "";
public int Health { get; set; }
public bool IsAlive { get; set; }
}
// Objekt zur Serialisierung
var player = new Player { Name = "Aragorn", Health = 100, IsAlive = true };
// Objekt in JSON‑String umwandeln
string json = JsonSerializer.Serialize(player);
// In Datei speichern — sicher!
File.WriteAllText("player.json", json);
// Objekt aus Datei wiederherstellen:
string loadedJson = File.ReadAllText("player.json");
Player loadedPlayer = JsonSerializer.Deserialize<Player>(loadedJson)!;
XML‑Serialisierung (wenn ein striktes Format nötig ist)
using System.Xml.Serialization;
// Die Klasse muss einen öffentlichen parameterlosen Konstruktor haben
var player = new Player { Name = "Aragorn", Health = 100, IsAlive = true };
var serializer = new XmlSerializer(typeof(Player));
using (var fs = File.Create("player.xml"))
{
serializer.Serialize(fs, player);
}
Visuelles Schema „alt vs neu“
| Aufgabe | Alter Weg (BinaryFormatter) | Moderner Weg |
|---|---|---|
| Serialisierung in Datei | |
|
| Deserialisierung aus Datei | |
|
| Sicherheit | Angreifbar (RCE) | Sichere Parser und strikte Modelle |
| Cross‑Plattform | Nein | Ja (JSON/XML/Protobuf) |
| Geschwindigkeit | Schnell, aber gefährlich | Schnell und sicher |
5. Typische Fehler bei der Arbeit mit XmlSerializer
Fehler Nr. 1: private Properties oder Felder. XmlSerializer serialisiert nur public Properties; sogar protected führt zu Problemen.
Fehler Nr. 2: Fehlender Standardkonstruktor. Ein öffentlicher parameterloser Konstruktor ist nötig, sonst klappt die Serialisierung/Deserialisierung nicht.
Fehler Nr. 3: Typeninkompatibilität. XmlSerializer arbeitet schlecht mit Dictionary, interface und delegate — benutzt Wrapper oder andere Formate.
Fehler Nr. 4: Zyklische Referenzen (circular reference). XmlSerializer unterstützt keine Graphen wie A → B → A; für solche Fälle nimmt man meist JSON mit passenden Einstellungen.
GO TO FULL VERSION