MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Serializarea în JSON cu JsonSerializer

JSON (JavaScript Object Notation) este unul dintre cele mai populare formate pentru stocarea și transferul datelor. Platforma .NET oferă funcționalități pentru lucrul cu JSON.

Funcționalitatea principală pentru lucrul cu JSON este concentrată în spațiul de nume System.Text.Json. Tipul cheie este clasa JsonSerializer, care permite serializarea unui obiect în JSON și, invers, deserializarea codului JSON într-un obiect C#.

Pentru a salva un obiect în JSON, clasa JsonSerializer definește metoda statică Serialize() și versiunea sa asincronă SerializeAsync(), care au mai multe versiuni supraîncărcate. Câteva dintre acestea sunt:

  • string Serialize(Object obj, Type type, JsonSerializerOptions options): serializă un obiect obj de tip type și returnează codul JSON ca șir de caractere. Parametrul opțional options permite setarea unor opțiuni suplimentare de serializare
  • string Serialize<T>(T obj, JsonSerializerOptions options): o versiune tipizată care serializă un obiect obj de tip T și returnează codul JSON ca șir de caractere
  • Task SerializeAsync(Stream utf8Json, Object obj, Type type, JsonSerializerOptions options): serializă un obiect obj de tip type și îl scrie într-un flux utf8Json. Parametrul opțional options permite setarea unor opțiuni suplimentare de serializare
  • Task SerializeAsync<T>(Stream utf8Json, T obj, JsonSerializerOptions options): o versiune tipizată care serializă un obiect obj de tip T într-un flux utf8Json

Pentru deserializarea codului JSON într-un obiect C#, se utilizează metoda Deserialize() și versiunea sa asincronă DeserializeAsync(), care au diferite versiuni. Câteva dintre acestea sunt:

  • object? Deserialize(string json, Type type, JsonSerializerOptions options): deserializă un șir JSON într-un obiect de tip type și returnează obiectul deserializat. Parametrul opțional options permite setarea unor opțiuni suplimentare de deserializare
  • T? Deserialize<T>(string json, JsonSerializerOptions options): deserializă un șir JSON într-un obiect de tip T și returnează acest obiect
  • ValueTask<object?> DeserializeAsync(Stream utf8Json, Type type, JsonSerializerOptions options, CancellationToken token): deserializă datele dintr-un flux utf8Json, care reprezintă un obiect JSON, într-un obiect de tip type. Parametrii opționali options și token permit setarea unor opțiuni suplimentare de deserializare și anularea sarcinii
  • ValueTask<T?> DeserializeAsync<T>(Stream utf8Json, JsonSerializerOptions options, CancellationToken token): deserializă datele dintr-un flux utf8Json, care reprezintă un obiect JSON, într-un obiect de tip T

Să vedem un exemplu simplu de serializare și deserializare a unui obiect:

using System.Text.Json;

Person tom = new Person("Tom", 37);
string json = JsonSerializer.Serialize(tom);
Console.WriteLine(json);
Person? restoredPerson = JsonSerializer.Deserialize<Person>(json);
Console.WriteLine(restoredPerson?.Name); // Tom

class Person
{
   public string Name { get; }
   public int Age { get; set; }
   public Person(string name, int age)
   {
       Name = name;
       Age = age;
   }
}

În acest exemplu, serializăm obiectul de tip Person într-un șir JSON folosind metoda JsonSerializer.Serialize(). Apoi, restaurăm acest obiect din șirul JSON folosind metoda JsonSerializer.Deserialize().

Ieșirea în consolă:

{"Name":"Tom","Age":37}
Tom

Deși în exemplul de mai sus s-a serializat/deserializat un obiect de clasă, putem serializa/deserializa și structuri în mod similar.

Observații privind serializarea/deserializarea

Obiectul care urmează să fie deserializat trebuie să aibă fie un constructor fără parametri, fie un constructor pentru care există valori corespunzătoare pentru toți parametrii în obiectul JSON deserializat (corespondența între parametrii constructorului și proprietățile obiectului JSON este stabilită pe baza denumirilor, ignorându-se sensibilitatea la majuscule).

Doar proprietățile publice ale obiectului (cu modificatorul public) sunt serializate.

Scrierea și citirea fișierelor JSON

Deoarece metodele SerializeAsync/DeserializeAsync pot primi un flux de tip Stream, putem utiliza un flux de fișiere pentru a salva și extrage datele ulterior:

using System.Text.Json;

// salvarea datelor
using (FileStream fs = new FileStream("user.json", FileMode.OpenOrCreate))
{
   Person tom = new Person("Tom", 37);
   await JsonSerializer.SerializeAsync<Person>(fs, tom);
   Console.WriteLine("Datele au fost salvate în fișier");
}

// citirea datelor
using (FileStream fs = new FileStream("user.json", FileMode.OpenOrCreate))
{
   Person? person = await JsonSerializer.DeserializeAsync<Person>(fs);
   Console.WriteLine($"Nume: {person?.Name}  Vârstă: {person?.Age}");
}

class Person
{
   public string Name { get; }
   public int Age { get; set; }
   public Person(string name, int age)
   {
       Name = name;
       Age = age;
   }
}

În acest exemplu, datele sunt salvate mai întâi într-un fișier user.json și apoi sunt citite din acesta.

Configurarea serializării cu JsonSerializerOptions

În mod implicit, JsonSerializer serializă obiectele într-un cod minimizat. Cu ajutorul parametrului suplimentar de tip JsonSerializerOptions, putem personaliza mecanismul de serializare/deserializare folosind proprietățile JsonSerializerOptions. Câteva dintre proprietățile sale sunt:

  • AllowTrailingCommas: stabilește dacă trebuie adăugată o virgulă după ultimul element din JSON. Dacă valoarea este true, se adaugă o virgulă
  • DefaultIgnoreCondition: stabilește dacă proprietățile cu valori implicite trebuie serializate/deserializate în JSON
  • IgnoreReadOnlyProperties: stabilește dacă proprietățile doar pentru citire trebuie serializate
  • WriteIndented: stabilește dacă trebuie adăugate spații în JSON (pentru lizibilitate). Dacă valoarea este true, se adaugă spații suplimentare

Exemplu de utilizare:

using System.Text.Json;

Person tom = new Person("Tom", 37);

var options = new JsonSerializerOptions
{
   WriteIndented = true
};
string json = JsonSerializer.Serialize<Person>(tom, options);
Console.WriteLine(json);
Person? restoredPerson = JsonSerializer.Deserialize<Person>(json);
Console.WriteLine(restoredPerson?.Name);

Ieșirea în consolă:

{
        "Name": "Tom",
        "Age":  37
}
Tom

Configurarea serializării cu ajutorul atributelor

În mod implicit, toate proprietățile publice sunt serializate. În plus, în obiectul JSON de ieșire, toate denumirile proprietăților corespund denumirilor proprietăților obiectului C#. Cu toate acestea, folosind atributele JsonIgnore și JsonPropertyName, putem ajusta acest comportament.

  • JsonIgnore: permite excluderea unei proprietăți din serializare
  • JsonPropertyName: permite înlocuirea denumirii originale a unei proprietăți

Exemplu de utilizare:

using System.Text.Json;
using System.Text.Json.Serialization;

Person tom = new Person("Tom", 37);

string json = JsonSerializer.Serialize<Person>(tom);
Console.WriteLine(json);
Person? person = JsonSerializer.Deserialize<Person>(json);
Console.WriteLine($"Nume: {person?.Name}  Vârstă: {person?.Age}");

class Person
{
   [JsonPropertyName("firstname")]
   public string Name { get; }
   [JsonIgnore]
   public int Age { get; set; }
   public Person(string name, int age)
   {
       Name = name;
       Age = age;
   }
}

În acest exemplu, proprietatea Age va fi ignorată, iar pentru proprietatea Name va fi utilizat pseudonimul "firstname". Ieșirea în consolă:

{"firstname":"Tom"}
Nume: Tom   Vârstă: 0

Observați că, deoarece proprietatea Age nu a fost serializată, la deserializare se utilizează valoarea implicită pentru aceasta.

← Lecția anterioară Lecția următoare →