1. Introducción
Newtonsoft.Json es una especie de dinosaurio en el buen sentido. Fue el estándar de facto para trabajar con JSON en el ecosistema .NET durante muchos años, incluso antes de que System.Text.Json apareciera. Millones de proyectos, miles de librerías y frameworks (incluso muchas partes de ASP.NET Core hasta hace poco) usaban Json.NET.
Sus ventajas son:
- Rico en funcionalidades y muy flexible: Json.NET ofrece un montón de opciones, atributos y posibilidades para personalizar el proceso de serialización y deserialización. Puede hacer cosas que System.Text.Json o las hace con dificultad o directamente no las soporta.
- Tolerante con JSON "no perfecto": los datos provenientes de sistemas externos no siempre son perfectos — Json.NET suele ser más permisivo y permite deserializar sin tanto dolor.
- Retrocompatible: si un proyecto o librería depende de Json.NET, saber trabajar con él sigue siendo necesario.
Claro, System.Text.Json es más rápido y fue pensado con requisitos modernos. Pero Newtonsoft.Json sigue siendo una herramienta potente, especialmente si necesitas lógica específica o máxima flexibilidad.
¿Cómo instalar Newtonsoft.Json?
Como es una librería externa, añade el paquete vía NuGet:
- Abre el proyecto.
- Haz clic derecho sobre el proyecto en Solution Explorer.
- Selecciona "Manage NuGet Packages...".
- En la búsqueda escribe Newtonsoft.Json.
- Selecciona el paquete y pulsa "Install".
Después de la instalación aparecerá una nueva dependencia — ¡ya puedes usar Json.NET!
Comparación de capacidades entre Newtonsoft.Json y System.Text.Json
| Funcionalidad | System.Text.Json | Newtonsoft.Json |
|---|---|---|
| Serialización/deserialización simple | Sí | Sí |
| Soporte de atributos para propiedades | Parcial | Completo |
| Convertidores personalizados | Sí | Sí |
| Trabajo con campos privados | No | Sí |
| Trabajo con estructuras dinámicas | Limitado | Sí |
| LINQ to JSON (JObject/JArray) | No | Sí |
| Reference Loop Handling | Sí | Sí |
| Soporte para DataTable, DataSet y tipos complejos | No | Sí |
| Rendimiento | Mejor | Bueno |
2. Ejemplo de serialización y deserialización de un objeto simple
Tomemos una estructura de juego común, que iremos expandiendo a lo largo de las lecciones:
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; }
}
Ahora guardemos el objeto Player en JSON y lo recuperemos:
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 }
};
// Serialización a cadena JSON
string json = JsonConvert.SerializeObject(player1, Formatting.Indented);
Console.WriteLine(json);
// Deserialización de nuevo al objeto Player
Player player2 = JsonConvert.DeserializeObject<Player>(json);
Console.WriteLine($"Nombre: {player2.Name}, salud: {player2.Health}");
¿Todo? Sí, casi, pero esto es solo la punta del iceberg. Vamos a ver por qué Newtonsoft.Json es más interesante y flexible que otras librerías.
3. Formateo, ajustes y parámetros avanzados
Cuando serializas un objeto, puedes obtener tanto una cadena compacta como un JSON bonito y legible. El comportamiento se controla con parámetros y ajustes.
Ejemplo: Diferentes variantes de formateo
// JSON bonito y legible
string prettyJson = JsonConvert.SerializeObject(player1, Formatting.Indented);
// JSON compacto "minificado"
string compactJson = JsonConvert.SerializeObject(player1, Formatting.None);
Ajustes de serialización
Si necesitas, pasa JsonSerializerSettings para un control fino:
var settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore, // Omitir campos con valor null
DefaultValueHandling = DefaultValueHandling.Ignore, // Omitir campos con valor por defecto
Formatting = Formatting.Indented
};
string customJson = JsonConvert.SerializeObject(player1, settings);
Obtienes control total sobre el formato de salida: quieres omitir campos vacíos — adelante. Necesitas serializar incluso propiedades privadas — configura el contrato.
4. Control de campos y propiedades con atributos
Newtonsoft.Json soporta un sistema potente de atributos que configuran la serialización directamente en la clase.
JsonProperty — Renombrar propiedades
Si el protocolo JSON requiere otro nombre de campo:
public class Player
{
[JsonProperty("player_name")]
public string Name { get; set; }
// ...
}
JSON resultante:
{ "player_name": "Aragorn", ... }
JsonIgnore — Ignorar una propiedad
public class Player
{
[JsonIgnore]
public int Health { get; set; }
}
Ahora el campo Health desaparecerá durante la serialización.
JsonConverter — Conversiones personalizadas
Permite indicar qué converter usar para procesar un campo concreto.
public class Player
{
[JsonConverter(typeof(InventoryToStringConverter))]
public List<string> Inventory { get; set; }
}
(Más sobre converters — abajo.)
5. Trabajo con objetos anidados y colecciones
Json.NET maneja muy bien objetos anidados, arrays, colecciones y diccionarios.
Ejemplo: Diccionarios
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);
El JSON resultante será así:
{
"Scores": {
"Alice": 1023,
"Bob": 999
}
}
6. Estructuras complejas: referencias cíclicas, Self-Referencing Objects
A veces los objetos se referencian entre sí. Newtonsoft.Json soporta la serialización de esas estructuras mediante ajustes especiales.
Ejemplo: Resolver referencias cíclicas
public class Person
{
public string Name { get; set; }
public Person Parent { get; set; }
public List<Person> Children { get; set; }
}
// Configuramos la serialización para ciclos
var settings = new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore // o .Serialize
};
Person p1 = new Person { Name = "Papá" };
Person p2 = new Person { Name = "Hijo", Parent = p1 };
p1.Children = new List<Person> { p2 };
string json = JsonConvert.SerializeObject(p1, settings);
Console.WriteLine(json);
Por defecto, si dejas ReferenceLoopHandling = Error, obtendrás una excepción. Esto protege de una serialización infinita accidental.
7. Trabajo con estructuras dinámicas: JObject, JArray
Cuando la estructura JSON no es conocida de antemano o cambia en tiempo de ejecución, usa objetos dinámicos sin tipado estricto en C#.
Tipos principales:
- JObject — representación de un objeto JSON.
- JArray — representación de un array.
using Newtonsoft.Json.Linq;
// Convertir una cadena a JObject
string json = @"{ 'name': 'Aragorn', 'health': 100 }";
JObject obj = JObject.Parse(json);
Console.WriteLine((string)obj["name"]); // Aragorn
Console.WriteLine((int)obj["health"]); // 100
// Añadir propiedades dinámicamente
obj["class"] = "Ranger";
Console.WriteLine(obj.ToString());
Iterar sobre un array
string jsonArr = @"['apple', 'banana', 'cherry']";
JArray array = JArray.Parse(jsonArr);
foreach (JToken item in array)
{
Console.WriteLine(item);
}
8. Soporte de versionado y campos obligatorios
El formato JSON puede cambiar, pueden faltar campos. Usa atributos y ajustes:
- [JsonProperty(Required = Required.Always)] — exigir la presencia del campo (si no, excepción).
- [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] — rellenar con el valor por defecto si falta el campo.
public class Player
{
[JsonProperty(Required = Required.Always)]
public string Name { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
[DefaultValue(50)]
public int Health { get; set; }
}
9. Conversión de fechas y formatos de tiempo
Trabajar con fechas suele requerir un formato explícito.
var dateSettings = new JsonSerializerSettings
{
DateFormatString = "yyyy-MM-dd"
};
string json = JsonConvert.SerializeObject(DateTime.Now, dateSettings);
Console.WriteLine(json); // "2024-06-15"
Y de vuelta al deserializar:
string dateJson = "\"2024-06-15\""; // ¡Fíjate: eso es una cadena entre comillas!
DateTime dt = JsonConvert.DeserializeObject<DateTime>(dateJson);
Console.WriteLine(dt);
GO TO FULL VERSION