En .NET podés trabajar con JSON usando dos enfoques principales:
A continuación verás ambos, con ejemplos equivalentes.
Usaremos esta clase y una lista para los ejemplos:
public class Producto
{
public int Codigo { get; set; }
public string Descripcion { get; set; } = "";
public decimal Precio { get; set; }
public bool Disponible { get; set; }
public List<string> Tags { get; set; } = new();
}
// Alternativa moderna
public record ProductoRecord(
int Codigo,
string Descripcion,
decimal Precio,
bool Disponible,
List<string> Tags
);
Más sobre records en C#.
using System.Text.Json;
var prod = new Producto {
Codigo = 101,
Descripcion = "Teclado mecánico",
Precio = 1200.50m,
Disponible = true,
Tags = new() { "periférico", "oferta" }
};
string json = JsonSerializer.Serialize(prod);
// {"Codigo":101,"Descripcion":"Teclado mecánico","Precio":1200.50,"Disponible":true,"Tags":["periférico","oferta"]}
var jsonString = """
{
"Codigo": 102,
"Descripcion": "Mouse inalámbrico",
"Precio": 850.75,
"Disponible": false,
"Tags": ["periférico"]
}
""";
Producto? prod2 = JsonSerializer.Deserialize<Producto>(jsonString);
JsonSerializerOptions
)var options = new JsonSerializerOptions
{
WriteIndented = true, // pretty-print
PropertyNamingPolicy = JsonNamingPolicy.CamelCase, // camelCase en JSON
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
};
string jsonPretty = JsonSerializer.Serialize(prod, options);
// Con CamelCase, la propiedad C# Codigo → "codigo" en el JSON.
using System.Text.Json.Serialization;
public class ProductoApi
{
[JsonPropertyName("id")] public int Codigo { get; set; }
[JsonPropertyName("title")] public string Descripcion { get; set; } = "";
[JsonIgnore] public bool Disponible { get; set; } // no se serializa
[JsonInclude] public List<string> Tags { get; set; } = new();
}
using System.Text.Json.Serialization;
var options = new JsonSerializerOptions
{
Converters = { new JsonStringEnumConverter() }, // enums como strings
WriteIndented = true
};
// DateTime usa ISO 8601 por defecto; para formato custom, crear un JsonConverter<DateTime> personalizado.
var lista = new List<Producto> { prod, prod2! };
string jsonLista = JsonSerializer.Serialize(lista, options);
var lista2 = JsonSerializer.Deserialize<List<Producto>>(jsonLista);
using System.Text.Json;
await File.WriteAllTextAsync("producto.json", jsonPretty);
using var stream = File.OpenRead("producto.json");
var prod3 = await JsonSerializer.DeserializeAsync<Producto>(stream);
try
{
var obj = JsonSerializer.Deserialize<Producto>("{ invalid json ");
}
catch (JsonException ex)
{
Console.WriteLine($"JSON inválido: {ex.Message}");
}
Elegilo si necesitás: LINQ-to-JSON (JObject/JToken), soporte avanzado de conversores, TypeNameHandling
, ReferenceLoopHandling
, etc.
dotnet add package Newtonsoft.Json
using Newtonsoft.Json;
var json = JsonConvert.SerializeObject(prod);
// Deserializar
var prod2 = JsonConvert.DeserializeObject<Producto>(json);
var settings = new JsonSerializerSettings
{
Formatting = Formatting.Indented, // pretty-print
NullValueHandling = NullValueHandling.Ignore, // omitir nulls
Culture = System.Globalization.CultureInfo.InvariantCulture
};
string jsonNice = JsonConvert.SerializeObject(prod, settings);
using Newtonsoft.Json;
public class ProductoApi2
{
[JsonProperty("id")] public int Codigo { get; set; }
[JsonProperty("title")] public string Descripcion { get; set; } = "";
[JsonIgnore] public bool Disponible { get; set; }
}
var settings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
Converters = { new Newtonsoft.Json.Converters.StringEnumConverter() } // enum como string
};
// Para DateTime, podés usar DateParseHandling/DateFormatString
settings.DateFormatString = "yyyy-MM-ddTHH:mm:ss.fffK";
var jsonLista = JsonConvert.SerializeObject(lista, settings);
var lista2 = JsonConvert.DeserializeObject<List<Producto>>(jsonLista);
File.WriteAllText("producto.json", jsonNice);
var data = File.ReadAllText("producto.json");
var prod3 = JsonConvert.DeserializeObject<Producto>(data);
using Newtonsoft.Json.Linq;
string jsonStr = """
{ "codigo": 101, "extras": { "color": "negro", "stock": 20 } }
""";
JObject obj = JObject.Parse(jsonStr);
int codigo = (int)obj["codigo"]!;
string color = (string?)obj["extras"]?["color"] ?? "N/A";
// Ideal cuando el esquema es dinámico o parcialmente desconocido.
Usando System.Net.Http.Json:
using System.Net.Http;
using System.Net.Http.Json; // helpers útiles
var http = new HttpClient { BaseAddress = new Uri("https://miapi.com/") };
var nuevo = new Producto { Codigo = 201, Descripcion = "Monitor 24\"", Precio = 150000m, Disponible = true };
// POST (usa JsonContent y System.Text.Json internamente)
HttpResponseMessage resp = await http.PostAsJsonAsync("productos", nuevo);
if (resp.IsSuccessStatusCode)
{
// GET parseado a objeto directo
var productos = await http.GetFromJsonAsync<List<Producto>>("productos");
}
System.Net.Http.Json
simplifica mucho: GetFromJsonAsync<T>
, PostAsJsonAsync
, etc.
var http = new HttpClient();
var content = new StringContent(JsonConvert.SerializeObject(nuevo), System.Text.Encoding.UTF8, "application/json");
var resp = await http.PostAsync("https://miapi.com/productos", content);
var body = await resp.Content.ReadAsStringAsync();
var lista = JsonConvert.DeserializeObject<List<Producto>>(body);
// System.Text.Json a Dictionary<string, object?>
var dict = JsonSerializer.Deserialize<Dictionary<string, object?>>("""
{
"codigo": 101,
"descripcion": "Teclado",
"precio": 1200.5
}
""");
// Nota: los valores pueden venir como JsonElement; para escenarios muy dinámicos, JObject de Newtonsoft es más cómodo.
Rendimiento: System.Text.Json (muy alto) / Newtonsoft (alto)
Dependencia: Incluido en .NET / Paquete NuGet externo
Opciones: NamingPolicy, IgnoreCondition / NullValueHandling, DefaultValueHandling
Converters: JsonConverter, JsonStringEnumConverter / Converters variados
Dinámico: JsonDocument/JsonNode (limitado) / JObject/JToken (potente)
Ecosistema: Muy bueno / Excelente y maduro
Regla práctica:
JsonPropertyName
/ JsonProperty
).JsonIgnore
, NullValueHandling.Ignore
).JsonException
/ JsonReaderException
).double
— usá decimal
.using System.Text.Json;
using System.Text.Json.Serialization;
var opciones = new JsonSerializerOptions
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
var productos = new List<Producto>
{
new() { Codigo = 1, Descripcion = "Teclado", Precio = 1200.50m, Disponible = true, Tags = new(){ "periférico" } },
new() { Codigo = 2, Descripcion = "Mouse", Precio = 850.75m, Disponible = false }
};
// Guardar en archivo
await File.WriteAllTextAsync("productos.json", JsonSerializer.Serialize(productos, opciones));
// Leer de archivo
var jsonLeido = await File.ReadAllTextAsync("productos.json");
var productosCargados = JsonSerializer.Deserialize<List<Producto>>(jsonLeido, opciones);
Console.WriteLine($"Cargados: {productosCargados?.Count}");
JObject/JToken
, conversores avanzados o compatibilidad con librerías existentes.