Neu in .NET 7.0 [22]: Angepasste JSON-Serialisierung mit Type Info Resolvers

Das Anpassen der Serialisierung und Deserialisierung von JSON-Inhalten ist nĂĽtzlich, wenn die zu serialisierende Klasse nicht im Sourcecode verfĂĽgbar ist.

vorlesen Druckansicht

(Bild: Blackboard/Shutterstock.com)

Lesezeit: 1 Min.
Von
  • Dr. Holger Schwichtenberg

Der neuere, in .NET Core 3.0 eingeführte JSON-Serializer System.Text.Json bietet seit Version 7.0 eine Anpassbarkeit der Serialisierung über sogenannte Type Info Resolver. So kann man die Serialisierung und Deserialisierung anpassen, ohne die zu betreffende .NET-Klasse verändern zu müssen. Das ist hilfreich, falls die zu (de-)serialisierende .NET-Klasse nicht im Quellcode vorliegt.

Der Dotnet-Doktor – Holger Schwichtenberg
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.

System.Text.Json ist zusammen mit .NET 7.0 als NuGet-Paket erschienen, läuft aber auch unter .NET Standard 2.0 und damit auch auf .NET Core 2.x/3.x sowie .NET 5.0/.NET 6.0 auf dem klassischen .NET Framework ab Version 4.6.2.

Videos by heise

Der Programmcode im Listing sorgt dafĂĽr, dass

  • bei Serialisierung- und Deserialisierung der Klasse Punkt die Property Memo ignoriert wird und
  • die Koordinaten X und Y (beide als Zahl vom Typ "int" deklariert) auch aus Zeichenketten wie "123" und "456" deserialisierbar sind.

Die Eigenschaft TypeInfoResolver in den JsonSerializerOptions ist vom Typ IJsonTypeInfoResolver.


/// <summary>
/// Zu serialiserende Datenklasse
/// </summary>
public class Point
{
 public int X { get; set; }
 public int Y { get; set; }
 public string Memo { get; set; } = "?";
}

public class FCL_JSON
{
 /// <summary>
 /// Type Info Resolver = Einflussnahme auf die 
 /// (De-)Serialisierung, ohne Datenklasse verändern zu müssen
 /// Verwendet Datenklasse Point
 /// </summary>
 public static void JSON_TypeInfoResolver()
 {
  CUI.H2(nameof(JSON_TypeInfoResolver));

  JsonSerializerOptions options = new()
  {
   TypeInfoResolver = new DefaultJsonTypeInfoResolver()
   {
    Modifiers =
    {
      (JsonTypeInfo jsonTypeInfo) =>
      {
        // Ignoriere alle Properties, die mit "Memo" beginnen
        var memoProp = 
          jsonTypeInfo.Properties.FirstOrDefault(p=>p.Name.StartsWith("Memo"));
        if (memoProp != null)
        {
          jsonTypeInfo.Properties.Remove(memoProp);
        }
            
        // Erlaube Zahlen aus Zeichenketten zu deserialisieren
        if (jsonTypeInfo.Type == typeof(int))
        {
          jsonTypeInfo.NumberHandling =
              JsonNumberHandling.AllowReadingFromString;
        }
       }
      }
    }
  };
  // Serialisierung

  var p1 = new Point() { X = 1, Y = 2, Memo = "Testpunkt" };
  var json1 = JsonSerializer.Serialize(p1, options);
  Console.WriteLine(json1); // Ausgabe: {"X":1,"Y":2}

  // Deserialisierung
  string json2 = """
   {
     "X":"123","Y":"456","Memo":"Testposition"
   }
   """;
  Console.WriteLine("Angepasste Deserialisierung von\n" + json2);
  Point? p2 = JsonSerializer.Deserialize<Point>(json2, options);
  if (p2 is not null) Console.WriteLine($"({p2.X},{p2.Y},{p2.Memo})"); 
  // Ausgabe: (123,456,?)
 }

Weitere Möglichkeiten, die Type Info Resolver einzusetzen, behandelt ein Blogbeitrag.

(rme)