csharp-serializacion-json-xml

Qué es y cómo usar la serialización en C# con JSON y XML

  • 5 min

La serialización es el proceso de convertir un objeto en un formato que pueda guardarse o transmitirse.

Hasta ahora, nuestros objetos viven felices en la memoria RAM mientras el programa se ejecuta. Pero, ¿qué pasa si cerramos el programa? Puf, desaparecen.

¿Y si queremos guardar el estado de un videojuego en el disco duro? ¿O enviar los datos de un cliente a una API Web en la otra punta del mundo? No podemos enviar la memoria RAM tal cual.

La serialización convierte el estado de un objeto en un formato de datos transportable (como una cadena de texto JSON, XML o una secuencia de bytes).

La Deserialización es el proceso inverso: reconstruir el objeto en memoria a partir de esos datos.

¿Por qué serializamos?

Principalmente para dos cosas:

  1. Persistencia: Guardar objetos en archivos o bases de datos para “revivirlos” más tarde.
  2. Transmisión: Enviar objetos a través de una red (HTTP/REST, Sockets) entre diferentes sistemas.

En .NET, tenemos varias formas de serializar, pero hoy en día el rey indiscutible es JSON.

Serialización JSON con System.Text.Json

Durante años, la librería de terceros Newtonsoft.Json fue el estándar de facto. Sin embargo, desde .NET Core 3.0, Microsoft introdujo System.Text.Json.

Es la librería nativa, moderna, segura y extremadamente optimizada para el rendimiento (trabaja con Span<T> y memoria de bajo nivel).

Serializar un objeto a texto

Supongamos que tenemos esta clase:

public class Usuario
{
    public int Id { get; set; }
    public string Nombre { get; set; }
    public string Email { get; set; }
    public bool Activo { get; set; }
}
Copied!

Para convertir una instancia de Usuario a un string JSON:

using System.Text.Json;

Usuario user = new Usuario 
{ 
    Id = 1, 
    Nombre = "Luis Llamas", 
    Email = "[email protected]", 
    Activo = true 
};

string jsonString = JsonSerializer.Serialize(user);

Console.WriteLine(jsonString);
// Salida (minificada por defecto):
// {"Id":1,"Nombre":"Luis Llamas","Email":"[email protected]","Activo":true}
Copied!

Deserializar texto a un objeto

El camino inverso es igual de sencillo. Usamos el método genérico Deserialize<T>.

string json = @"{ ""Id"": 1, ""Nombre"": ""Luis"" }";

Usuario userRecuperado = JsonSerializer.Deserialize<Usuario>(json);

Console.WriteLine(userRecuperado.Nombre); // Imprime: Luis
Copied!

Fijaos que la propiedad Email y Activo no venían en el JSON. Al deserializar, esas propiedades en el objeto C# tendrán sus valores por defecto (null y false).

Opciones de configuración (JsonSerializerOptions)

Por defecto, System.Text.Json es estricto y rápido. Pero el mundo real es desordenado. A menudo necesitamos personalizar cómo se genera el JSON.

Por ejemplo, es un estándar en la web usar camelCase (minúscula inicial) para las propiedades (userName), mientras que en C# usamos PascalCase (UserName).

var opciones = new JsonSerializerOptions
{
    WriteIndented = true, // JSON bonito y legible (con espacios)
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase // Convierte Nombre -> nombre
};

string jsonBonito = JsonSerializer.Serialize(user, opciones);

/* Salida:
{
  "id": 1,
  "nombre": "Luis Llamas",
  "email": "[email protected]",
  "activo": true
}
*/
Copied!

Atributos de control

A veces necesitamos un control granular sobre propiedades específicas. Para eso usamos atributos directamente en nuestra clase.

  1. [JsonPropertyName]: Para cuando el nombre en el JSON es totalmente diferente al de C#.
  2. [JsonIgnore]: Para evitar serializar datos sensibles o internos.
using System.Text.Json.Serialization;

public class Producto
{
    // En el JSON aparecerá como "product_id" (típico de APIs antiguas)
    [JsonPropertyName("product_id")]
    public int Id { get; set; }

    public string Nombre { get; set; }

    // Esto NUNCA se guardará en el JSON ni se leerá
    [JsonIgnore]
    public double CosteInterno { get; set; }
}
Copied!

Serialización XML (XmlSerializer)

Aunque JSON domina el mundo web, XML sigue muy vivo en configuraciones de empresa y sistemas antiguos (SOAP).

En .NET usamos System.Xml.Serialization.XmlSerializer.

Requisitos especiales para XML:

  1. La clase debe ser public.
  2. Debe tener un constructor sin parámetros (el constructor por defecto).
using System.Xml.Serialization;

// 1. Creamos el serializador indicando el tipo
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Usuario));

// 2. Necesitamos un Stream o un Writer donde escribir
using (StringWriter writer = new StringWriter())
{
    xmlSerializer.Serialize(writer, user);
    string xmlOutput = writer.ToString();
    
    Console.WriteLine(xmlOutput);
}
Copied!

La salida será algo así:

<?xml version="1.0" encoding="utf-16"?>
<Usuario>
  <Id>1</Id>
  <Nombre>Luis Llamas</Nombre>
  <Email>[email protected]</Email>
  <Activo>true</Activo>
</Usuario>
Copied!

XML es más verboso (ocupa más espacio) que JSON, pero soporta esquemas (XSD) y es más estricto con la estructura.

El peligro de la serialización binaria (BinaryFormatter)

Históricamente, C# tenía una clase llamada BinaryFormatter que convertía objetos a binario puro. Era muy cómoda porque guardaba incluso los campos privados.

ADVERTENCIA DE SEGURIDAD: Microsoft ha marcado BinaryFormatter como obsoleto y peligroso. En .NET 9, la implementación incluida en el runtime se eliminó y sus métodos lanzan excepción.

No lo uses con datos que no sean de confianza. Tiene vulnerabilidades graves que pueden permitir ejecutar código si un atacante controla el archivo serializado.

Si necesitas serialización binaria de alto rendimiento (por ejemplo, para videojuegos o sistemas en tiempo real), usa bibliotecas modernas como MessagePack o Protobuf. Otra opción es utilizar System.Text.Json y convertir el texto a bytes UTF-8.