CodeGym /Cursos /C# SELF /Serialização com System.Te...

Serialização com System.Text.Json

C# SELF
Nível 44 , Lição 3
Disponível

1. Introdução

Por muito tempo, no ecossistema .NET a principal ferramenta para trabalhar com JSON foi o ótimo pacote de terceiros Newtonsoft.Json (também conhecido como Json.NET). Ele é poderoso, flexível e ainda é amplamente usado. Mas com a chegada das novas versões .NET 9 e C# 14, a Microsoft decidiu que era hora de ter um serializador JSON embutido e de alto desempenho. Assim surgiu o System.Text.Json.

Por que uma nova abordagem? O System.Text.Json foi projetado com as realidades modernas em mente e resolve problemas que se acumularam ao longo dos anos usando bibliotecas de terceiros. Ele é otimizado para máxima velocidade e segurança, é ideal para cenários assíncronos e web APIs, e — o melhor — não precisa ser instalado via NuGet: já vem na plataforma.

Claro, o Newtonsoft.Json não desapareceu, e vamos ver ele depois. Mas para a maioria dos projetos novos o System.Text.Json é a escolha padrão. Prepare-se, agora vamos ensinar nossos objetos a falar a língua JSON!

2. Fundamentos do trabalho com System.Text.Json

Serialização simples de um objeto

Então, vamos começar com a mágica básica. Vamos serializar nosso objeto para uma string JSON.

using System;
using System.Text.Json; // Não esqueça de adicionar!

public class Player
{
    public string Name { get; set; }
    public int Health { get; set; }
    public bool IsAlive { get; set; }
}

// Em algum lugar do seu programa:
Player player = new Player { Name = "Aragorn", Health = 100, IsAlive = true };

// Serialização:
string json = JsonSerializer.Serialize(player);
Console.WriteLine(json); // Vai imprimir: {"Name":"Aragorn","Health":100,"IsAlive":true}

Comentário: Se você acabou de começar a estudar serialização, esse exemplo mostra como tudo é simples: JsonSerializer.Serialize — e pronto.

Desserialização de um objeto

Vamos reviver um objeto a partir de uma string JSON:

string incomingJson = "{\"Name\":\"Legolas\",\"Health\":88,\"IsAlive\":true}";

Player player2 = JsonSerializer.Deserialize<Player>(incomingJson);
Console.WriteLine(player2.Name);   // Legolas
Console.WriteLine(player2.Health); // 88
Console.WriteLine(player2.IsAlive); // true

Comentário: Se a estrutura do JSON coincide com a sua classe — tudo funciona direitinho. Se não — podem ocorrer exceções ou valores padrão.

3. Princípios de funcionamento e arquitetura da serialização

Como acontece o mapeamento

O System.Text.Json por padrão usa os mesmos nomes das propriedades que estão na classe. Case-sensitive! Se no JSON estiver escrito health em vez de Health, a desserialização não vai funcionar — a propriedade ficará com o valor padrão (0, false ou null).

Por exemplo:

// JSON com chaves em minúsculas:
string badJson = "{\"name\":\"Gimli\",\"health\":120,\"isAlive\":true}";
Player player3 = JsonSerializer.Deserialize<Player>(badJson);
Console.WriteLine(player3.Name);    // vazio
Console.WriteLine(player3.Health);  // 0
Console.WriteLine(player3.IsAlive); // false

Curiosidade: Muitos APIs usam chaves em camelCase (health), enquanto em C# é comum usar PascalCase (Health). Isso é resolvido com configurações (veja abaixo).

4. Controle da serialização — opções e configurações

Formatando o JSON: saída "legível por humanos"

Às vezes você quer não um JSON compacto, mas um JSON bonito — para configs ou logs.

var options = new JsonSerializerOptions
{
    WriteIndented = true // Adicionar indentação
};

string prettyJson = JsonSerializer.Serialize(player, options);
Console.WriteLine(prettyJson);
/*
{
  "Name": "Frodo",
  "Health": 50,
  "IsAlive": true,
  "Inventory": [
    "Ring",
    "Bread",
    "Torch"
  ],
  "Position": {
    "X": 5,
    "Y": 15
  }
}
*/

A propriedade WriteIndented é usada, e o serializador adiciona indentação e quebras de linha.

Controlando o estilo de nomes (CamelCase vs PascalCase)

Se você está trabalhando com uma web API onde todas as chaves são camelCase, ative a política de nomes:

var options = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};

string camelCaseJson = JsonSerializer.Serialize(player, options);
// {"name":"Frodo","health":50,"isAlive":true,"inventory":["Ring","Bread","Torch"],"position":{"x":5,"y":15}}

Assim, na desserialização essas chaves serão mapeadas corretamente:

string apiJson = "{\"name\":\"Bilbo\",\"health\":40,\"isAlive\":true,\"inventory\":[\"Mug\"],\"position\":{\"x\":10,\"y\":5}}";
Player bilbo = JsonSerializer.Deserialize<Player>(apiJson, options);
Console.WriteLine(bilbo.Name); // Bilbo

5. Dicas úteis

Usando o atributo [JsonIgnore]

Às vezes nem todas as propriedades devem ser serializadas — por exemplo, dados privados ou valores temporários calculados.

using System.Text.Json.Serialization;

public class Player
{
    public string Name { get; set; }
    public int Health { get; set; }

    [JsonIgnore] // Essa propriedade não vai para o JSON
    public bool IsSecretCharacter { get; set; }
}

Agora, ao serializar:

var player = new Player { Name = "Boromir", Health = 80, IsSecretCharacter = true };
string json = JsonSerializer.Serialize(player);
Console.WriteLine(json); // {"Name":"Boromir","Health":80}

Ao desserializar de volta, IsSecretCharacter receberá o valor padrão (false).

Usando [JsonPropertyName("...")]

Suponha que no código a propriedade se chame IsAlive, mas no JSON ela deve ser "status":

using System.Text.Json.Serialization;

public class Player
{
    public string Name { get; set; }
    public int Health { get; set; }

    [JsonPropertyName("status")]
    public bool IsAlive { get; set; }
}

A serialização agora ficará assim:

var player = new Player { Name = "Pippin", Health = 60, IsAlive = false };
string json = JsonSerializer.Serialize(player);
Console.WriteLine(json); // {"Name":"Pippin","Health":60,"status":false}

E ao desserializar, a chave "status" vai preencher corretamente a propriedade IsAlive.

Limitações embutidas e características de segurança

  • Por padrão só são serializadas propriedades públicas com getters/setters; campos/propriedades privados são ignorados.
  • Em caso de referências cíclicas é lançada uma exceção: "A possible object cycle was detected".
  • Diferente do Newtonsoft.Json, o serializador padrão depende menos de "truques" mágicos com tipos — em contrapartida é mais seguro e mais rápido para cenários típicos.

6. Erros comuns e armadilhas

Você muda o nome de uma propriedade no JSON e esquece de atualizar o código — como resultado a propriedade recebe o valor padrão (null, 0, false).

O campo necessário está ausente no JSON — a propriedade correspondente do objeto ficará com o valor default (veja a documentação).

Uma propriedade não tem um setter público — na desserialização ela não será preenchida.

Você mudou a estrutura de classes aninhadas ou coleções — a desserialização pode quebrar ou produzir resultados inesperados.

Nomes iguais em níveis diferentes de aninhamento (no pai e no objeto filho) confundem e dificultam o debug.

Às vezes a causa é a versão da plataforma: versões antigas do System.Text.Json tinham suporte pior para alguns tipos (por exemplo, Dictionary, DateTime, enum), mas em .NET 7/8/9 muita coisa foi corrigida.

2
Tarefa
C# SELF, nível 44, lição 3
Bloqueado
Desserialização usando JsonPropertyName
Desserialização usando JsonPropertyName
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION