1. Einführung
So sehr man auch hoffen möchte, dass Collections “out of the box” perfekt serialisiert und deserialisiert werden, in echten Projekten ist das oft nicht der Fall. Manchmal muss man bestimmte Collections von der Serialisierung ausschließen — z.B. interne gecachte Daten. Es kann nötig sein, kolektionseigene Properties umzubenennen, damit sie dem API-Vertrag entsprechen. In manchen Fällen ist es wichtig zu steuern, welche Elemente gespeichert oder ignoriert werden, oder die Collection speziell zu transformieren, damit das finale JSON für andere Dienste verständlich und “lesbar” ist.
Glücklicherweise bietet System.Text.Json einen einfachen und transparenten Weg, die Serialisierung mit Attributen zu steuern, die man sowohl auf Collections als auch auf einzelne Elemente anwenden kann. In diesem Abschnitt bauen wir unser Bibliotheksmodell weiter aus, um praktisch zu sehen, wie das funktioniert.
2. Ausschluss von Collection-Properties: [JsonIgnore]
Fangen wir mit dem Einfachen an. Manchmal hat deine Klasse eine Collection, die nicht serialisiert werden soll — z.B. temporäre, gecachte oder sensitive Daten. Was tun? Natürlich [JsonIgnore]!
Stell dir vor, wir haben eine Klasse Library, in die wir eine Property List<Book> Cache eingefügt haben, die nur für schnellen Zugriff verwendet wird:
using System.Text.Json.Serialization;
public class Library
{
public string Name { get; set; }
public List<Book> Books { get; set; }
[JsonIgnore]
public List<Book> Cache { get; set; } // Wird nicht serialisiert!
}
// Beispielnutzung:
var library = new Library
{
Name = "Hauptbibliothek",
Books = new List<Book>
{
new Book { Title = "Die Zaubertal", Author = new Author { Name = "Tove Jansson", BirthYear = 1914 } }
},
Cache = new List<Book>
{
new Book { Title = "Herr der Fliegen", Author = new Author { Name = "William Golding", BirthYear = 1911 } }
}
};
string json = JsonSerializer.Serialize(library, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine(json); // Im JSON gibt es keine Property Cache!
Das Serialisierungsergebnis sieht ungefähr so aus:
{
"Name": "Hauptbibliothek",
"Books": [
{
"Title": "Die Zaubertal",
"Author": {
"Name": "Tove Jansson",
"BirthYear": 1914
}
}
]
}
Siehst du? Keine “Caches” in der Außenwelt. Alles, was mit [JsonIgnore] markiert ist, ist versteckt und sicher, wie ein WLAN-Passwort in deinem Kopf.
3. Umbenennen von Collections mit [JsonPropertyName]
Oft trifft man auf APIs, die z.B. "items" statt "Books" erwarten. Oder du willst das Feld in C# nicht umbennenen (um Verwirrung zu vermeiden), aber im JSON soll es anders heißen?
So geht das:
using System.Text.Json.Serialization;
public class Library
{
public string Name { get; set; }
[JsonPropertyName("items")]
public List<Book> Books { get; set; }
[JsonIgnore]
public List<Book> Cache { get; set; }
}
// Serialisierung:
var library = new Library { Name = "Filiale Nr.1", Books = new List<Book>() };
string json = JsonSerializer.Serialize(library, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine(json);
Ausgabe:
{
"Name": "Filiale Nr.1",
"items": []
}
Beachte, dass die Deserialisierung ebenfalls korrekt das JSON-Feld items auf Books in C# mappt — die Magie funktioniert in beide Richtungen.
4. Steuerung der Serialisierung von Collections und deren Elementen
Dafür brauchst du JsonIgnoreCondition.WhenWritingNull und/oder nullable.
Es kommt vor, dass eine Collection einfach ein optionales Feld ist. Zum Beispiel hat eine frisch erstellte Bibliothek noch keine Bücher. Wenn du nicht möchtest, dass im JSON das Property books: null auftaucht, kannst du das über Optionen steuern:
var library = new Library { Name = "Leere Bibliothek" };
// Books ist nicht initialisiert = null
var options = new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
WriteIndented = true
};
string json = JsonSerializer.Serialize(library, options);
Console.WriteLine(json);
Ergebnis:
{
"Name": "Leere Bibliothek"
}
Wenn du hingegen eine leere Liste hast (aber nicht null), wird der Serializer "books": [] ausgeben. Das ist ein wichtiges Detail, weil man manchmal ein Feld bewusst verbergen will, wenn es null ist, aber nicht, wenn es eine leere Collection ist.
5. Attribut [JsonIgnore] auf Properties der Elemente
Serialisierungsattribute funktionieren auch innerhalb der Elemente einer Collection. Du kannst einzelne Properties jedes Objekts in der Liste verbergen.
public class Book
{
public string Title { get; set; }
public Author Author { get; set; }
[JsonIgnore]
public string InternalCode { get; set; }
}
Beim Serialisieren eines Buchs aus der Collection Books wird das Feld InternalCode nicht im JSON erscheinen.
6. Adressierung von Collections über “Indizes” oder verschachtelte Strukturen
Manchmal serialisiert man Collections nicht einfach als Arrays, sondern z.B. als “maps” (Dictionary) — wenn jedes Buch eine eindeutige ID hat. In diesem Fall braucht man keine speziellen Element-Attribute, sondern kann schlicht ein Dictionary-Property deklarieren:
public class Library
{
[JsonPropertyName("catalog")]
public Dictionary<string, Book> BookCatalog { get; set; }
}
Beim Serialisieren wird das Dictionary zu einem Objekt mit Key-Value-Paaren:
var library = new Library
{
BookCatalog = new Dictionary<string, Book>
{
["978-5-699-12345-6"] = new Book { Title = "Wörterbuch", Author = new Author { Name = "Unbekannt", BirthYear = 2000 } }
}
};
JSON:
{
"catalog": {
"978-5-699-12345-6": {
"Title": "Wörterbuch",
"Author": {
"Name": "Unbekannt",
"BirthYear": 2000
}
}
}
}
Diese Darstellung ist praktisch für API-Szenarien, in denen die Verbindung zwischen Key und Objekt wichtig ist.
7. Fehler und Schwierigkeiten bei der Steuerung der Serialisierung von Collections
Wenn man versucht, eine Collection zu serialisieren, deren nicht alle Elemente korrekt initialisiert sind (z.B. es gibt null-Einträge in der Liste), wird System.Text.Json solche Elemente per Standard als null im Array schreiben.
Selbst wenn DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull gesetzt ist, bleiben null-Elemente innerhalb eines Arrays erhalten — die Regel gilt für Properties von Objekten, nicht für den Inhalt von Collections. Um das zu vermeiden, bereinige die Collection vorher: RemoveAll(b => b == null).
Eine häufige Verwirrung bei der Deserialisierung ist Namensinkongruenz. Wenn du vergisst, [JsonPropertyName] anzugeben, erwartet die Klasse das Property Books, du schickst aber JSON mit items: dann wird die Collection nicht gefüllt und bleibt leer. Prüfe immer die korrekten Namen!
8. Tabelle: wo die wichtigsten Attribute anwendbar sind
| Attribut | Kann auf Collections angewendet werden? | Kann auf Collection-Elemente angewendet werden? | Beispiele für Nutzung |
|---|---|---|---|
|
ja | ja | Liste oder Feld innerhalb von Book verbergen |
|
ja | ja | Books → items oder Title → name umbenennen |
|
ja | ja | Private Properties in die Serialisierung einschließen |
|
ja | ja | Spezial-Converter für eine Liste zuweisen |
9. Schema der Serialisierung von Collections mit Attributen
+-------------+
| Library |
+-------------+
| Name -- serialisiert als "Name"
| Books -- [JsonPropertyName("items")], serialisiert als "items": [...]
| Cache -- [JsonIgnore], wird nicht serialisiert
| BookCatalog -- [JsonPropertyName("catalog")], serialisiert als "catalog": {...}
JSON-Ergebnis ungefähr so:
{
"Name": "Stadtbibliothek",
"items": [
{
"Title": "1984",
"Author": {
"Name": "George Orwell",
"BirthYear": 1903
}
},
{
"Title": "Große Erwartungen",
"Author": {
"Name": "Charles Dickens",
"BirthYear": 1812
}
}
],
"catalog": {
"978-1234567890": {
"Title": "Der Ruf von Cthulhu",
"Author": {
"Name": "Howard Phillips Lovecraft",
"BirthYear": 1890
}
}
}
}
10. Praktische Bedeutung und Besonderheiten in Interviews und echten Projekten
Im produktiven Einsatz muss man immer den Vertrag des externen API und die Anforderungen an die Serialisierung berücksichtigen. Du solltest wissen, wie man interne Collections “versteckt”, wie man Namenskonventionen und -stile einhält und in manchen Fällen die Serialisierungs-Schema je nach Client-Version dynamisch ändert.
Typische Interviewfragen:
- Wie serialisiert man nur einen Teil der Daten?
- Wie sorgt man dafür, dass ein Collection-Property nicht ins JSON gelangt?
- Wie mappt man Namen von Properties in C# und JSON, wenn sie unterschiedlich sind?
- Kann man einzelne Elemente innerhalb einer Collection von der Serialisierung ausschließen (z.B. vertrauliche Informationen)?
Die Antworten drehen sich um korrektes Verwenden von Attributen und Serialisierungsoptionen: [JsonIgnore], [JsonPropertyName], JsonSerializerOptions und ums durchdachte Vorgehen beim Umgang mit dem Inhalt von Collections.
GO TO FULL VERSION