json-serializacion-deserializacion-nanoframework

Serializar y deserializar JSON en nanoFramework

  • 4 min

JSON es un formato de texto para representar datos estructurados que resulta muy cómodo en aplicaciones IoT.

Hemos aprendido a hacer peticiones HTTP (Cliente) y a responderlas (Servidor). Pero hay un problema incómodo que hemos estado evitando: El formato de los datos.

En los ejemplos anteriores, construíamos las respuestas concatenando cadenas: string json = "{ \"valor\": " + temperatura + " }";

Esto es una aberración. Es propenso a errores (¿te faltó una comilla?), difícil de mantener y horrible de leer. Además, cuando recibimos datos complejos de una API, “parsearlos” buscando comas y corchetes manualmente es una pesadilla.

La solución es la Serialización.

  • Serializar: Convertir un Objeto C# en vivo (en memoria RAM) a una cadena de texto JSON.
  • Deserializar: Convertir una cadena de texto JSON en un Objeto C# listo para usar.

En esta entrada aprenderemos a usar la librería nanoFramework.Json para automatizar ambas conversiones.

Para este tutorial necesitas instalar el paquete NuGet: nanoFramework.Json

La librería nanoFramework.Json

En el .NET “grande” (escritorio/web) estamos acostumbrados a usar System.Text.Json o el clásico Newtonsoft.Json. Sin embargo, esas librerías son gigantescas y consumen mucha memoria, algo que no nos sobra en un microcontrolador.

nanoFramework.Json ofrece una API adaptada a las restricciones de memoria de un microcontrolador.

Deserializar texto en un objeto

Imagina que hacemos una petición GET a una API del tiempo y nos devuelve esto:

{
  "ciudad": "Madrid",
  "temperatura": 24.5,
  "humedad": 60,
  "activo": true
}
Copied!

Para trabajar con esto en C#, lo primero es crear una Clase (o struct) que represente esa estructura.

public class DatosTiempo
{
    public string Ciudad { get; set; }
    public double Temperatura { get; set; }
    public int Humedad { get; set; }
    public bool Activo { get; set; }
}
Copied!

Ahora, convertir el texto en un objeto es una sola línea de código:

using System.Diagnostics;
using nanoFramework.Json; // <--- Importante

// ... Supongamos que 'jsonRecibido' es el string que nos dio el HttpClient
string jsonRecibido = "{ \"Ciudad\": \"Madrid\", \"Temperatura\": 24.5, \"Humedad\": 60, \"Activo\": true }";

// Deserializamos
DatosTiempo miObjeto = (DatosTiempo)JsonConvert.DeserializeObject(jsonRecibido, typeof(DatosTiempo));

// ¡Ya podemos usar las propiedades con IntelliSense!
Debug.WriteLine($"En {miObjeto.Ciudad} hace {miObjeto.Temperatura} grados.");

if (miObjeto.Activo) 
{
    // Lógica compleja...
}
Copied!

Mucho mejor. Se acabó buscar subcadenas o hacer splits por comas.

Serializar un objeto como texto

El caso contrario es igual de importante. Queremos enviar la telemetría de nuestros sensores a la nube.

En lugar de crear el string a mano, creamos una instancia de nuestra clase y dejamos que la librería trabaje.

public class Telemetria
{
    public string IdDispositivo { get; set; }
    public double Voltaje { get; set; }
    public long Timestamp { get; set; }
}

// ...

// 1. Creamos el objeto y lo rellenamos
Telemetria datos = new Telemetria()
{
    IdDispositivo = "ESP32_01",
    Voltaje = 3.35,
    Timestamp = DateTime.UtcNow.Ticks
};

// 2. Serializamos
string jsonParaEnviar = JsonConvert.SerializeObject(datos);

Debug.WriteLine(jsonParaEnviar);
// Salida: {"IdDispositivo":"ESP32_01","Voltaje":3.35,"Timestamp":638337216000000000}
Copied!

Ahora puedes meter ese jsonParaEnviar directamente en el StringContent de tu petición POST (como vimos en la lección anterior).

Trabajar con arrays

¿Y si la API nos devuelve una lista de cosas? [{"id":1}, {"id":2}, {"id":3}]

nanoFramework maneja arrays perfectamente.

string jsonLista = "[{ \"IdDispositivo\": \"A1\", \"Voltaje\": 3.0 }, { \"IdDispositivo\": \"B2\", \"Voltaje\": 4.1 }]";

// Deserializamos a un Array de objetos
Telemetria[] listaSensores = (Telemetria[])JsonConvert.DeserializeObject(jsonLista, typeof(Telemetria[]));

foreach(var sensor in listaSensores)
{
    Debug.WriteLine($"Sensor {sensor.IdDispositivo} tiene {sensor.Voltaje}V");
}
Copied!

Consejos y limitaciones

Aunque la librería es potente, recuerda que estamos en un microcontrolador:

  1. Propiedades Públicas: El serializador solo ve las propiedades public. Si son privadas, las ignorará.
  2. Fechas (DateTime): JSON no define un tipo fecha. Acuerda un formato con la API (por ejemplo, ISO 8601 o una marca temporal) y, si el serializador no lo interpreta, recíbelo como string para convertirlo después.
  3. Memoria: Serializar objetos muy grandes (strings de 20KB) puede hacer que el ESP32 se quede sin RAM y lance una excepción. Intenta mantener los mensajes JSON pequeños y concisos.