1. Introdução
Se você está começando a se familiarizar com serialização no .NET, é natural perguntar: por que outra biblioteca se já existe o embutido System.Text.Json? A resposta é simples: Newtonsoft.Json surgiu antes e, ao longo dos anos, evoluiu até ser ainda a ferramenta mais flexível para JSON no .NET.
Ela virou um padrão de fato porque suporta cenários complexos: contratos customizados, conversores poderosos, serialização de campos privados, LINQ para JSON, objetos dinâmicos (JObject), tratamento flexível de referências cíclicas e vários formatos de data/hora. Muitas bibliotecas e APIs ainda usam Json.NET "por baixo dos panos".
Importante: em certos cenários o embutido System.Text.Json ainda fica atrás das possibilidades do Newtonsoft.Json, então vale a pena aprender Json.NET.
Como adicionar Newtonsoft.Json (Json.NET)
Instale o pacote via NuGet:
dotnet add package Newtonsoft.Json
Importe o namespace:
using Newtonsoft.Json;
2. Serialização com Newtonsoft.Json
Vamos pegar a classe tradicional Person:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
Serializando um objeto para string JSON
Person person = new Person { Name = "Ivan", Age = 30 };
// Serialização para JSON
string json = JsonConvert.SerializeObject(person);
Console.WriteLine(json);
// Saída: {"Name":"Ivan","Age":30}
Desserializando JSON de volta para um objeto
string json = "{\"Name\":\"Ivan\",\"Age\":30}";
Person person = JsonConvert.DeserializeObject<Person>(json);
Console.WriteLine($"{person.Name}, {person.Age}");
// Saída: Ivan, 30
O que acontece "por baixo do capô"?
Newtonsoft.Json itera por todas as propriedades públicas (public), serializa elas em JSON e escreve na string. Ao desserializar ele mapeia as chaves do JSON para os nomes das propriedades e popula o objeto.
3. Serialização de coleções de objetos
Serializando coleções e arrays
Com coleções tudo funciona "out of the box".
List<Person> people = new List<Person>
{
new Person { Name = "Ivan", Age = 30 },
new Person { Name = "Maria", Age = 25 }
};
string json = JsonConvert.SerializeObject(people);
// Saída: [{"Name":"Ivan","Age":30},{"Name":"Maria","Age":25}]
List<Person> deserialized = JsonConvert.DeserializeObject<List<Person>>(json);
// Agora você tem novamente uma lista de Person!
Particularidades na serialização e desserialização de dicionários
var dict = new Dictionary<string, int>
{
["apple"] = 2,
["banana"] = 5
};
string json = JsonConvert.SerializeObject(dict);
// Saída: {"apple":2,"banana":5}
var deserializedDict = JsonConvert.DeserializeObject<Dictionary<string,int>>(json);
// Tudo funcionando!
Se as chaves não forem strings (por exemplo, Dictionary<int,string>), o Json.NET converte as chaves para strings ao serializar, e ao desserializar tenta converter de volta. Para chaves complexas (ex.: Guid) é mais seguro usar Dictionary<string, TValue>.
4. Trabalho com objetos aninhados e hierarquias
public class Order
{
public int Id { get; set; }
public Person Customer { get; set; }
public List<Product> Products { get; set; }
}
public class Product
{
public string Title { get; set; }
public double Price { get; set; }
}
Order order = new Order
{
Id = 123,
Customer = new Person { Name = "Ivan", Age = 30 },
Products = new List<Product>
{
new Product { Title = "Notebook", Price = 50000.0 },
new Product { Title = "Mouse", Price = 1500.0 }
}
};
string json = JsonConvert.SerializeObject(order);
Console.WriteLine(json);
Resultado: objetos aninhados serão representados corretamente dentro da estrutura JSON.
5. Ajustando serialização com atributos
Ignorando uma propriedade
public class Person
{
public string Name { get; set; }
[JsonIgnore]
public int Age { get; set; }
}
Agora Age não vai aparecer no JSON.
Renomeando uma propriedade
public class Person
{
[JsonProperty("full_name")]
public string Name { get; set; }
}
No JSON o nome vai aparecer como "full_name".
6. Configuração flexível: JsonSerializerSettings
Formatação (JSON "bonitão" com múltiplas linhas):
string json = JsonConvert.SerializeObject(
people,
Formatting.Indented
);
Resultado:
[
{
"Name": "Ivan",
"Age": 30
},
{
"Name": "Maria",
"Age": 25
}
]
Configurações usadas com frequência:
| Propriedade | Descrição |
|---|---|
|
Como tratar propriedades null (omití-las ou escrever explicitamente null) |
|
Omitir valores padrão ou incluí-los |
|
O que fazer com referências cíclicas |
|
Formato de string para datas e horas |
Exemplo omitindo null:
string json = JsonConvert.SerializeObject(
person,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }
);
7. Trabalhando com estruturas JSON dinâmicas: JObject, JArray e afins
Quando a estrutura do JSON é desconhecida, use os tipos de Newtonsoft.Json.Linq:
using Newtonsoft.Json.Linq;
string json = @"{
'Name': 'Ivan',
'Age': 30,
'Skills': ['C#', 'SQL', 'JSON']
}";
JObject obj = JObject.Parse(json);
Console.WriteLine(obj["Name"]); // Ivan
Console.WriteLine(obj["Skills"][0]); // C#
Criando JSON "on the fly":
var jObj = new JObject
{
["Status"] = "Success",
["Result"] = new JArray("item1", "item2", "item3")
};
Console.WriteLine(jObj.ToString(Formatting.Indented));
JObject e JArray são representações de objeto e array JSON — basicamente coleções convenientes.
8. Dicas úteis
Referências cíclicas
Newtonsoft.Json consegue tratar referências cíclicas de forma flexível:
var settings = new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
string json = JsonConvert.SerializeObject(obj, settings);
Assim os ciclos são ignorados. Para preservar referências você pode usar ReferenceLoopHandling.Serialize junto com [JsonObject(IsReference = true)].
Serialização de objetos anônimos e dinâmicos
var anon = new { Foo = 42, Bar = "Hello" };
string json = JsonConvert.SerializeObject(anon);
// {"Foo":42,"Bar":"Hello"}
Validação e tratamento de erros
try
{
Person p = JsonConvert.DeserializeObject<Person>(brokenJson);
}
catch (JsonSerializationException ex)
{
Console.WriteLine("Erro ao desserializar: " + ex.Message);
}
Comparando Newtonsoft.Json vs System.Text.Json
| Newtonsoft.Json (Json.NET) | System.Text.Json (.NET) | |
|---|---|---|
| Suporte .NET | .NET Framework/Standard/6+ | .NET Core 3.0+ / .NET 5/6/9 |
| LINQ para JSON (JObject/JArray) | Sim | Não |
| Configuração flexível | Muito ampla | Limitada |
| Atributos ([JsonProperty], ...) | Sim | Sim (parcialmente, menos recursos) |
| Suporte a propriedades privadas | Sim | Não |
| Velocidade | Mais lento em alguns cenários | Mais rápido |
| Conversores complexos | Sim | Sim (menos flexível por enquanto) |
| Suporte a DataTable, DataSet | Sim | Não |
| Documentação e exemplos | Muitos | Crescendo |
9. Erros de iniciantes e armadilhas comuns
Erro #1: propriedades ficam null depois da desserialização.
Frequentemente a propriedade não tem setter ou falta um construtor sem parâmetros — o serializador não tem como preencher o objeto.
Erro #2: nomes de propriedades não batem entre JSON e classe.
Se no JSON o campo for "fullName" e na classe for FullName, use [JsonProperty] ou ajuste o ContractResolver para mapear nomes.
Erro #3: serialização funciona só com propriedades públicas por padrão.
Campos/propriedades privadas não são serializados sem configuração extra. Você vai precisar de conversores ou resolvers/contratos especiais.
Erro #4: referências cíclicas levam a StackOverflowException.
Referências mútuas entre objetos podem circular a serialização sem configuração. Ajuste o tratamento de referências (por exemplo, ReferenceLoopHandling) ou mude o modelo de dados.
GO TO FULL VERSION