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 |
|---|---|
|
Come gestire le proprietà null (saltarle o scrivere esplicitamente null) |
|
Saltare i valori di default o meno |
|
Cosa fare con i loop di riferimento |
|
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) | Sì | No |
| Configurazione flessibile | Molto ampia | Limitata |
| Attributi ([JsonProperty], ...) | Sì | Sì (parzialmente, meno possibilità) |
| Supporto proprietà private | Sì | No |
| Velocità | Più lenta in alcuni scenari | Più veloce |
| Converter complessi | Sì | Sì (meno flessibili, per ora) |
| Supporto DataTable, DataSet | Sì | 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.
GO TO FULL VERSION