Neu in .NET 8.0 [29]: Verbesserungen für den JSON-Source-Generator

Der Source Generator ist in .NET 8.0 wichtiger, damit die JSON-Serialisierung und -Deserialisierung auch AOT-Anwendungen funktioniert.​

In Pocket speichern vorlesen Druckansicht
Druckplatten mit Buchstaben

(Bild: RossEdwardCairney/Shutterstock.com)

Lesezeit: 2 Min.
Von
  • Dr. Holger Schwichtenberg

System.Text.Json nimmt im Standard das Mapping von JSON auf .NET-Objekte per Laufzeitcodegenerierung vor. Schon seit der Version 6.0 gibt es in System.Text.Json auch einen Source-Generator. Dieser erzeugt den Mapping-Code bereits zur Entwicklungszeit, sodass keine Laufzeitcodegenerierung notwendig ist. Der JSON-Source-Generator war (und ist) ein wichtiges Instrument für die Leistungsoptimierung.

Der Dotnet-Doktor – Holger Schwichtenberg

Dr. Holger Schwichtenberg ist technischer Leiter des Expertennetzwerks www.IT-Visions.de, das mit 53 renommierten Experten zahlreiche mittlere und große Unternehmen durch Beratungen und Schulungen sowie bei der Softwareentwicklung unterstützt. Durch seine Auftritte auf zahlreichen nationalen und internationalen Fachkonferenzen sowie mehr als 90 Fachbücher und mehr als 1500 Fachartikel gehört Holger Schwichtenberg zu den bekanntesten Experten für .NET und Webtechniken in Deutschland.

Mit Ausdehnung des Native-AOT-Compilers auf ASP.NET Core Web APIs ist er aber nochmals wichtiger geworden, denn bei Native AOT ist keine Laufzeitkompilierung möglich.

Die Serie zu den Neuerungen in .NET 8.0

Der JSON-Source-Generator bietet in System.Text.Json Version 8.0 folgende neuen Möglichkeiten:

  • Der Source Generator für JSON (Text.Json.SourceGeneration.JsonSourceGenerator) unterstützt nun auch die in C# 9.0 eingeführten Init-Only-Properties und die in C# 11.0 eingeführten Required Properties.
  • Entwickler können per Projekteinstellung dafür sorgen, dass System.Text.Json gar keine Laufzeitcodegenerierung mehr ausführt: <JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
  • Entwickler können im Programmcode mit einem statischen Mitglied abfragen, ob eine Laufzeitcodegenerierung möglich ist: IsReflectionEnabledByDefault
  • Zu den Neuerungen in System.Text.Json 8.0 gehört auch, dass die Annotation [JsonSourceGenerationOptions] nun alle Optionen bietet, die auch die Klasse JsonSerializerOptions beim imperativen Programmieren mit der Klasse Text.Json. JsonSerializer erlaubt.

Wenn die Laufzeitcodegenerierung im JSON-Serializer abgeschaltet ist, man aber dennoch eine Serialisierung ohne Source Generator versucht (etwa JsonSerializer.Serialize(new { value = 42 });), kassiert man folgende Fehlermeldung: "Reflection-based serialization has been disabled for this application. Either use the source generator APIs or explicitly configure the 'JsonSerializerOptions.TypeInfoResolver' property."

Wenn die Laufzeitcodegenerierung im JSON-Serializer abgeschaltet ist, muss man eine von JsonSerializerContext abgeleitete Klasse erschaffen, die per Annotation [JsonSerializable] die Verweise auf die zu (de)serialisierenden .NET-Klassen erhält. Optional kann man die Einstellung per [JsonSourceGenerationOptions] vornehmen.

Online-Konferenz zu .NET 9.0 am 9. November

In der Online-Konferenz betterCode() .NET 9.0 am 19. November 2024 von iX und dpunkt.verlag präsentieren .NET-Experten von www.IT-Visions.de den fertigen Stand von .NET 9.0 anhand von Praxisbeispielen. Dazu zählen die Neuerungen in .NET 9.0 SDK, C# 13.0, ASP.NET Core 9.0, Blazor 9.0, Windows Forms 9.0, WPF 9.0, WinUI, .NET MAUI 9.0 und die Integration von Künstlicher Intelligenz in .NET-Anwendungen. Das Programm bietet sechs Vorträge, eine Diskussion und sechs Workshops.

Tickets sind zum Frühbucherpreis erhältlich.

Die im folgenden Code verwendeten Klassen Consultant und Person waren bereits im Beispielcode zum vorherigen Teil der Serie:

[JsonSerializable(typeof(Address))]
[JsonSerializable(typeof(Person))] 
[JsonSerializable(typeof(Consultant))]
[JsonSourceGenerationOptions(PreferredObjectCreationHandling 
 =JsonObjectCreationHandling.Populate)]
 
internal partial class PersonJsonContext : JsonSerializerContext
{
}

Diese Klasse muss man dann in den Serialisierungsoptionen festlegen:

var options = new JsonSerializerOptions
{
 TypeInfoResolver = PersonJsonContext.Default
};

Das folgende Listing zeigt, dass in System.Text.Json nun ein erforderliches Mitglied, das beim Deserialisieren nicht befüllt wird, auch bei JSON-Source-Generator zum Laufzeitfehler führt.

try
{
 var jsonString = """
 {"FULL-NAME":"Holger Schwichtenberg","PERSONAL-WEBSITE":"www.dotnet-doktor.de"}
 """;
 Console.WriteLine("JSON: " + jsonString);
 var obj = JsonSerializer.Deserialize<Consultant>(jsonString, options);
 if (obj != null) CUI.Success(obj.ToString());
}
catch (Exception ex)
{
 CUI.PrintError(ex.Message); // JSON deserialization for type 'NET8Konsole.Consultant' was missing required properties, including the following: ID !!! Vor .NET 8.0 wäre hier in Verbindung mit Source Generator KEIN Laufzeitfehler aufgetreten. ID war = 0
}

(rme)