1. Introduzione
Newtonsoft.Json è una specie di dinosauro in senso buono. È stato lo standard de-facto per lavorare con JSON nell'ecosistema .NET per anni, molto prima che System.Text.Json emergesse. Milioni di progetti, migliaia di librerie e framework (anche molte parti di ASP.NET Core fino a poco tempo fa) hanno usato proprio Json.NET.
I suoi punti di forza sono:
- Ricco di funzionalità e flessibile: Json.NET offre tantissime opzioni, attributi e modi per personalizzare la serializzazione e la deserializzazione. Sa fare cose che System.Text.Json fa con fatica o non fa proprio.
- Tollerante verso JSON "non perfetto": i dati provenienti da sistemi esterni non sono sempre puliti — Json.NET è spesso più permissivo e permette di deserializzare con meno dolori.
- Retrocompatibile: se un progetto o una libreria dipendono da Json.NET, saperlo usare rimane importante.
Certo, System.Text.Json è più veloce ed è pensato per i requisiti moderni. Ma Newtonsoft.Json resta uno strumento potente, soprattutto quando serve logica specifica o massima flessibilità.
Come installare Newtonsoft.Json?
Essendo una libreria esterna, aggiungi il package tramite NuGet:
- Apri il progetto.
- Clic destro sul progetto in Solution Explorer.
- Scegli "Manage NuGet Packages...".
- Nel campo di ricerca digita Newtonsoft.Json.
- Seleziona il package e premi "Install".
Dopo l'installazione avrai la nuova dipendenza — puoi usare Json.NET!
Confronto delle funzionalità di Newtonsoft.Json e System.Text.Json
| Funzionalità | System.Text.Json | Newtonsoft.Json |
|---|---|---|
| Serializzazione/deserializzazione semplice | Sì | Sì |
| Supporto ad attributi per le proprietà | Parziale | Completo |
| Custom converters | Sì | Sì |
| Lavoro con campi privati | No | Sì |
| Lavoro con strutture dinamiche | Limitato | Sì |
| LINQ to JSON (JObject/JArray) | No | Sì |
| Reference Loop Handling | Sì | Sì |
| Supporto DataTable, DataSet e tipi complessi | No | Sì |
| Performance | Migliore | Buona |
2. Esempio di serializzazione e deserializzazione di un oggetto semplice
Prendiamo una struttura di gioco comune, che evolveremo nelle lezioni:
public class Player
{
public string Name { get; set; }
public int Health { get; set; }
public bool IsAlive { get; set; }
public List<string> Inventory { get; set; }
public Position Position { get; set; }
}
public class Position
{
public int X { get; set; }
public int Y { get; set; }
}
Ora salviamo l'oggetto Player in JSON e lo ripristiniamo:
using Newtonsoft.Json;
Player player1 = new Player
{
Name = "Aragorn",
Health = 100,
IsAlive = true,
Inventory = new List<string> { "sword", "bow", "healing potion" },
Position = new Position { X = 10, Y = 25 }
};
// Serializzazione in stringa JSON
string json = JsonConvert.SerializeObject(player1, Formatting.Indented);
Console.WriteLine(json);
// Deserializzazione di nuovo in oggetto Player
Player player2 = JsonConvert.DeserializeObject<Player>(json);
Console.WriteLine($"Nome: {player2.Name}, salute: {player2.Health}");
Tutto? Quasi, ma questa è solo la punta dell'iceberg. Vediamo perché Newtonsoft.Json è più interessante e flessibile rispetto ad altre librerie.
3. Formattazione, impostazioni e opzioni avanzate
Quando serializzi un oggetto, puoi ottenere sia una stringa compatta sia un JSON formattato. Il comportamento è controllato da parametri e impostazioni.
Esempio: Differenti varianti di formattazione
// JSON leggibile
string prettyJson = JsonConvert.SerializeObject(player1, Formatting.Indented);
// JSON compatto "minificato"
string compactJson = JsonConvert.SerializeObject(player1, Formatting.None);
Impostazioni di serializzazione
Se serve, passa JsonSerializerSettings per un controllo fine:
var settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore, // Saltare i campi con valore null
DefaultValueHandling = DefaultValueHandling.Ignore, // Saltare i campi col valore di default
Formatting = Formatting.Indented
};
string customJson = JsonConvert.SerializeObject(player1, settings);
Ottieni il massimo controllo sull'output: vuoi saltare i campi vuoti? fatto. Devi serializzare anche proprietà private? configura il contract.
4. Gestire campi e proprietà con attributi
Newtonsoft.Json supporta un sistema di attributi molto potente per personalizzare la serializzazione direttamente nelle classi.
JsonProperty — Rinominare le proprietà
Se il protocollo JSON richiede un nome diverso per un campo:
public class Player
{
[JsonProperty("player_name")]
public string Name { get; set; }
// ...
}
JSON risultante:
{ "player_name": "Aragorn", ... }
JsonIgnore — Ignorare una proprietà
public class Player
{
[JsonIgnore]
public int Health { get; set; }
}
Ora il campo Health non comparirà nella serializzazione.
JsonConverter — Conversioni custom
Permette di specificare quale converter usare per un campo specifico.
public class Player
{
[JsonConverter(typeof(InventoryToStringConverter))]
public List<string> Inventory { get; set; }
}
(Dettagli sui converter — più avanti.)
5. Lavorare con oggetti annidati e collezioni
Json.NET gestisce bene oggetti annidati, array, collezioni e dizionari.
Esempio: Dizionari
public class GameStats
{
public Dictionary<string, int> Scores { get; set; }
}
GameStats stats = new GameStats
{
Scores = new Dictionary<string, int>
{
["Alice"] = 1023,
["Bob"] = 999
}
};
string statsJson = JsonConvert.SerializeObject(stats, Formatting.Indented);
Console.WriteLine(statsJson);
Il JSON sarà così:
{
"Scores": {
"Alice": 1023,
"Bob": 999
}
}
6. Strutture complesse: riferimenti ciclici, Self-Referencing Objects
A volte gli oggetti contengono riferimenti reciproci. Newtonsoft.Json supporta la serializzazione di queste strutture tramite impostazioni dedicate.
Esempio: Risolvere riferimenti ciclici
public class Person
{
public string Name { get; set; }
public Person Parent { get; set; }
public List<Person> Children { get; set; }
}
// Configuriamo la serializzazione per i cicli
var settings = new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore // oppure .Serialize
};
Person p1 = new Person { Name = "Papa" };
Person p2 = new Person { Name = "Figlio", Parent = p1 };
p1.Children = new List<Person> { p2 };
string json = JsonConvert.SerializeObject(p1, settings);
Console.WriteLine(json);
Di default, se lasci ReferenceLoopHandling = Error, otterrai un'eccezione. Questo protegge da serializzazioni infinite accidentali.
7. Lavorare con strutture dinamiche: JObject, JArray
Quando la struttura JSON è sconosciuta a priori o cambia dinamicamente, usa oggetti dinamici senza forte tipizzazione C#.
Tipi principali:
- JObject — rappresentazione di un oggetto JSON.
- JArray — rappresentazione di un array.
using Newtonsoft.Json.Linq;
// Convertire una stringa in JObject
string json = @"{ 'name': 'Aragorn', 'health': 100 }";
JObject obj = JObject.Parse(json);
Console.WriteLine((string)obj["name"]); // Aragorn
Console.WriteLine((int)obj["health"]); // 100
// Aggiungere dinamicamente proprietà
obj["class"] = "Ranger";
Console.WriteLine(obj.ToString());
Iterare un array
string jsonArr = @"['apple', 'banana', 'cherry']";
JArray array = JArray.Parse(jsonArr);
foreach (JToken item in array)
{
Console.WriteLine(item);
}
8. Supporto per versioning e campi obbligatori
Il formato JSON può cambiare, alcuni campi possono mancare. Usa attributi e impostazioni:
- [JsonProperty(Required = Required.Always)] — richiede la presenza del campo (altrimenti eccezione).
- [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] — inserisce il default se il campo manca.
public class Player
{
[JsonProperty(Required = Required.Always)]
public string Name { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
[DefaultValue(50)]
public int Health { get; set; }
}
9. Conversione di date e formati temporali
Lavorare con le date spesso richiede un formato esplicito.
var dateSettings = new JsonSerializerSettings
{
DateFormatString = "yyyy-MM-dd"
};
string json = JsonConvert.SerializeObject(DateTime.Now, dateSettings);
Console.WriteLine(json); // "2024-06-15"
E al contrario durante la deserializzazione:
string dateJson = "\"2024-06-15\""; // Attenzione: è una stringa tra virgolette!
DateTime dt = JsonConvert.DeserializeObject<DateTime>(dateJson);
Console.WriteLine(dt);
GO TO FULL VERSION