CodeGym /Corsi /C# SELF /Immergiamoci in Newtonsoft...

Immergiamoci in Newtonsoft.Json

C# SELF
Livello 47 , Lezione 2
Disponibile

1. Introduzione

Se hai appena iniziato a conoscere la serializzazione in .NET, è naturale chiedersi: perché serve un'altra libreria se c'è già il built-in System.Text.Json? La risposta è semplice: Newtonsoft.Json è arrivata prima ed è evoluta in anni diventando ancora lo strumento più flessibile per JSON in .NET.

È diventata de-facto lo standard perché supporta scenari complessi: contratti custom, converter potenti, serializzazione di campi privati, LINQ su JSON, oggetti dinamici (JObject), gestione flessibile dei riferimenti ciclici e moltissimi formati di date/tempo. Molte librerie e API ancora usano Json.NET “sotto il cofano”.

Importante: in certi scenari il built-in System.Text.Json è ancora meno capace rispetto a Newtonsoft.Json, quindi imparare Json.NET rimane utile.

Come aggiungere Newtonsoft.Json (Json.NET)

Installa il package via NuGet:

dotnet add package Newtonsoft.Json

Importa lo namespace:

using Newtonsoft.Json;

2. Serializzazione con Newtonsoft.Json

Prendiamo la classica classe Person:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Serializzare un oggetto in una stringa JSON

Person person = new Person { Name = "Ivan", Age = 30 };

// Serializzazione in JSON
string json = JsonConvert.SerializeObject(person);

Console.WriteLine(json);
// Output: {"Name":"Ivan","Age":30}

Deserializzare JSON di nuovo in un oggetto

string json = "{\"Name\":\"Ivan\",\"Age\":30}";

Person person = JsonConvert.DeserializeObject<Person>(json);

Console.WriteLine($"{person.Name}, {person.Age}");
// Output: Ivan, 30

Cosa succede "sotto il cofano"?

Newtonsoft.Json itera tutte le proprietà pubbliche (public), le serializza in JSON e le scrive nella stringa. Durante la deserializzazione associa le chiavi dal JSON ai nomi delle proprietà e popola l'oggetto.

3. Serializzazione di collezioni di oggetti

Serializzare collezioni e array

Con le collezioni funziona “out of the box”.

List<Person> people = new List<Person>
{
    new Person { Name = "Ivan", Age = 30 },
    new Person { Name = "Maria", Age = 25 }
};

string json = JsonConvert.SerializeObject(people);
// Output: [{"Name":"Ivan","Age":30},{"Name":"Maria","Age":25}]

List<Person> deserialized = JsonConvert.DeserializeObject<List<Person>>(json);
// Ora hai di nuovo una lista di Person!

Particolarità nella serializzazione e deserializzazione dei dizionari

var dict = new Dictionary<string, int>
{
    ["apple"] = 2,
    ["banana"] = 5
};

string json = JsonConvert.SerializeObject(dict);
// Output: {"apple":2,"banana":5}

var deserializedDict = JsonConvert.DeserializeObject<Dictionary<string,int>>(json);
// Tutto OK!

Se le chiavi non sono stringhe (per esempio Dictionary<int,string>), Json.NET convertirà le chiavi in stringhe durante la serializzazione e cercherà di convertire indietro alla deserializzazione. Per chiavi complesse (per esempio Guid) è più sicuro usare Dictionary<string, TValue>.

4. Lavorare con oggetti annidati e gerarchie

public class Order
{
    public int Id { get; set; }
    public Person Customer { get; set; }
    public List<Product> Products { get; set; }
}
public class Product
{
    public string Title { get; set; }
    public double Price { get; set; }
}
Order order = new Order
{
    Id = 123,
    Customer = new Person { Name = "Ivan", Age = 30 },
    Products = new List<Product>
    {
        new Product { Title = "Notebook", Price = 50000.0 },
        new Product { Title = "Mouse", Price = 1500.0 }
    }
};

string json = JsonConvert.SerializeObject(order);

Console.WriteLine(json);

Risultato: gli oggetti annidati saranno rappresentati correttamente all'interno della struttura JSON.

5. Configurare la serializzazione con attributi

Ignorare una proprietà

public class Person
{
    public string Name { get; set; }

    [JsonIgnore]
    public int Age { get; set; }
}

Ora Age non finirà nel JSON.

Rinominare una proprietà

public class Person
{
    [JsonProperty("full_name")]
    public string Name { get; set; }
}

Nel JSON il nome sarà "full_name".

6. Configurazione flessibile: JsonSerializerSettings

Formattazione (JSON bello e multilinea):

string json = JsonConvert.SerializeObject(
    people,
    Formatting.Indented
);

Risultato:

[
  {
    "Name": "Ivan",
    "Age": 30
  },
  {
    "Name": "Maria",
    "Age": 25
  }
]

Impostazioni usate spesso:

Proprietà Descrizione
NullValueHandling
Come gestire le proprietà null (saltarle o scrivere esplicitamente null)
DefaultValueHandling
Saltare i valori di default o meno
ReferenceLoopHandling
Cosa fare con i loop di riferimento
DateFormatString
Formato delle stringhe per date e orari

Esempio per saltare i valori null:

string json = JsonConvert.SerializeObject(
    person,
    new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }
);

7. Lavorare con strutture JSON dinamiche: JObject, JArray e altri

Quando la struttura del JSON non è nota a priori, usa i tipi in Newtonsoft.Json.Linq:

using Newtonsoft.Json.Linq;

string json = @"{
    'Name': 'Ivan',
    'Age': 30,
    'Skills': ['C#', 'SQL', 'JSON']
}";

JObject obj = JObject.Parse(json);

Console.WriteLine(obj["Name"]);     // Ivan
Console.WriteLine(obj["Skills"][0]); // C#

Creare JSON "al volo":

var jObj = new JObject
{
    ["Status"] = "Success",
    ["Result"] = new JArray("item1", "item2", "item3")
};

Console.WriteLine(jObj.ToString(Formatting.Indented));

JObject e JArray sono le rappresentazioni di oggetto e array JSON, in pratica collezioni comode da usare.

8. Suggerimenti utili

Riferimenti ciclici

Newtonsoft.Json sa gestirli in modo flessibile:

var settings = new JsonSerializerSettings
{
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};

string json = JsonConvert.SerializeObject(obj, settings);

Così i loop vengono ignorati. Per preservare i riferimenti puoi usare ReferenceLoopHandling.Serialize insieme a [JsonObject(IsReference = true)].

Serializzazione di oggetti anonimi e dinamici

var anon = new { Foo = 42, Bar = "Hello" };
string json = JsonConvert.SerializeObject(anon);
// {"Foo":42,"Bar":"Hello"}

Validazione e gestione degli errori

try
{
    Person p = JsonConvert.DeserializeObject<Person>(brokenJson);
}
catch (JsonSerializationException ex)
{
    Console.WriteLine("Errore durante la deserializzazione: " + ex.Message);
}

Confronto Newtonsoft.Json vs System.Text.Json

Newtonsoft.Json (Json.NET) System.Text.Json (.NET)
Supporto .NET .NET Framework/Standard/6+ .NET Core 3.0+ / .NET 5/6/9
LINQ su JSON (JObject/JArray) No
Configurazione flessibile Molto ampia Limitata
Attributi ([JsonProperty], ...) Sì (parzialmente, meno possibilità)
Supporto proprietà private No
Velocità Più lenta in alcuni scenari Più veloce
Converter complessi Sì (meno flessibili, per ora)
Supporto DataTable, DataSet No
Documentazione ed esempi Moltissimi In crescita

9. Errori dei principianti e trappole tipiche

Errore №1: le proprietà diventano null dopo la deserializzazione.
Spesso la proprietà non ha un setter oppure manca un costruttore senza parametri — il serializer non ha modo di popolare l'oggetto.

Errore №2: mismatch dei nomi delle proprietà tra JSON e classe.
Se nel JSON il campo è "fullName", mentre nella classe è FullName, usa [JsonProperty] o configura un ContractResolver per mappare i nomi.

Errore №3: la serializzazione lavora solo con proprietà pubbliche di default.
Campi/proprietà private non vengono serializzati senza impostazioni aggiuntive. Servono converter o resolver/contract speciali.

Errore №4: riferimenti ciclici causano StackOverflowException.
Riferimenti reciproci tra oggetti possono creare loop di serializzazione senza le opportune impostazioni. Configura il comportamento dei riferimenti (per esempio ReferenceLoopHandling) o modifica il modello dati.

Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION