Die neue Version 9.0 von System.Text.Json bringt eine Vielzahl an Funktionen, die JSON-Schema-Generierung und intelligente Anwendungen unterstützen. Ausserdem wurden zahlreiche von Nutzern gewünschte Verbesserungen wie Nullable-Referenztypen, flexible Indentation und die Anpassung von Enum-Namen hinzugefügt.
JSON-Schema-Exporter
Ein Highlight der neuen Version ist der JsonSchemaExporter. Dieser erzeugt JSON-Schemadokumente basierend auf .NET-Typen. Mit nur wenigen Zeilen Code lässt sich so das Serialisierungsformat einer Klasse als JSON-Schema ausgeben. Dies ist besonders hilfreich, um den Aufbau und die Anforderungen an JSON-Daten zu dokumentieren. Die Konfiguration der Schemadaten erfolgt durch den Einsatz von JsonSerializerOptions oder JsonTypeInfo, was Anpassungen an Benennungsrichtlinien und Typdarstellung ermöglicht.
Mit Optionen wie JsonSchemaExporterOptions können sogar benutzerdefinierte Transformationen für das Schema angewendet werden, was den Export noch flexibler gestaltet.
Mehrere JSON-Dokumente streamen
Der Utf8JsonReader kann nun mehrere JSON-Dokumente lesen, die durch Leerzeichen getrennt in einem einzigen Puffer oder Stream vorliegen. Standardmässig wirft er eine Exception, wenn nach dem ersten Top-Level-Dokument weitere Zeichen folgen, die keine Leerzeichen sind. Mit dem Flag JsonReaderOptions.AllowMultipleValues lässt sich dieses Verhalten jedoch ändern und ermöglicht so das Lesen von JSON-Daten mit ungültigen, angehängten Inhalten. Für die Streaming-Deserialisierung gibt es jetzt die neue Methode JsonSerializer.DeserializeAsyncEnumerable, die das Streamen mehrerer Top-Level-Objekte erlaubt. Standardmässig streamt sie Elemente in einem Top-Level-JSON-Array, kann jedoch über das neue topLevelValues-Flag angepasst werden.
Nullable-Annotationen beachten
Das JsonSerializer bietet nun eingeschränkte Unterstützung für die Durchsetzung der Nullable-Annotationen von Referenztypen bei der (De-)Serialisierung. Mit dem Flag RespectNullableAnnotations können Entwickler die Einhaltung von Nullable-Referenzen aktivieren. Allerdings gibt es hier einige Einschränkungen: Die Überprüfung greift nur bei nicht-generischen Eigenschaften, Feldern und Konstruktorparametern. Top-Level-Typen, generische Parameter und Elemente in Sammlungen (wie List<string> vs. List<string?>) werden nicht berücksichtigt. Um Null-Werte dennoch gezielt zu verhindern, kann ein benutzerdefinierter Konverter genutzt werden.
Zusätzlich führt .NET 9 das Flag RespectRequiredConstructorParameters ein, welches nicht-optional deklarierte Konstruktorparameter zwingend erwartet. Standardmässig behandelt STJ alle Parameter als optional, doch mit diesem Flag wird eine striktere Prüfung aktiviert. Beide Flags – RespectNullableAnnotations und RespectRequiredConstructorParameters – lassen sich über Projekteinstellungen global aktivieren und sind standardmässig optional, um die Rückwärtskompatibilität zu gewährleisten. Für neue Projekte wird jedoch empfohlen, beide Optionen zu nutzen, um die Typensicherheit zu erhöhen.
Anpassung der Enum-Namen
Mit dem neuen Attribut JsonStringEnumMemberName können Entwickler die Namen einzelner Enum-Werte für die JSON-Repräsentation individuell anpassen.
Lesereihenfolge von Metadaten
In bisherigen Versionen von System.Text.Json mussten Metadatenfelder wie $id und $type stets am Anfang eines JSON-Objekts stehen. Die neue Option AllowOutOfOrderMetadataProperties hebt diese Einschränkung auf und ermöglicht das Deserialisieren von JSON-Daten aus nicht-STJ-Quellen, die eine andere Anordnung der Metadaten verwenden.
Benutzerdefinierte Indentation
Mit .NET 9 bieten die JsonWriterOptions und JsonSerializerOptions neue APIs zur Steuerung der Einrückung bei der JSON-Formatierung. Ein Beispiel dafür ist die Möglichkeit, die Einrückung mit einem Tab anstelle von Leerzeichen festzulegen.
Der JsonObject-Typ, der die mutable DOM für JSON-Objekte darstellt, erhält nun zusätzliche APIs zur besseren Verwaltung der Eigenschaftsreihenfolge. Obwohl JsonObject als IDictionary<string, JsonNode> modelliert ist, kann die Reihenfolge der Eigenschaften jetzt gezielt gesteuert werden.
Für die Tiefenvergleichbarkeit wurde das JsonElement.DeepEquals-Methoden hinzugefügt, die eine umfassende Vergleichsmöglichkeit für JsonElement-Instanzen bietet und JsonNode.DeepEquals ergänzt. Diese Methoden berücksichtigen dabei auch die Gleichwertigkeit verschiedener numerischer Darstellungen in JSON.
Leistung und Optimierung
Auch die Performance hat in System.Text.Json signifikante Verbesserungen erfahren. So gab es Optimierungen in der Serialisierungsgeschwindigkeit und in der speichereffizienten Verarbeitung grosser JSON-Datenströme.