Para definir valores padrão globais de JsonSerializerOptions no ASP.NET Core, configure-os uma única vez na inicialização: AddJsonOptions() para controladores, ConfigureHttpJsonOptions() para endpoints de APIs mínimas ou AddNewtonsoftJson() para devolver a serialização ao Json.NET.
Por padrão, o ASP.NET Core serializa JSON com o System.Text.Json, e não com o Newtonsoft.Json. É assim desde o ASP.NET Core 3.0, e é o que uma Web API criada no .NET 10 faz hoje. A seguir, configuramos as três opções e mostramos quais endpoints cada uma alcança.
Antes de entrar no assunto, recomendamos o nosso artigo sobre serialização e desserialização em C#.
Agora, vamos em frente.
O que é JsonSerializerOptions?
JsonSerializerOptions é o objeto de configuração que o System.Text.Json lê toda vez que serializa ou desserializa um objeto. Ele fica no namespace System.Text.Json e é passado como parâmetro para JsonSerializer.Serialize() e JsonSerializer.Deserialize().
Cinco propriedades fazem a maior parte do trabalho. PropertyNamingPolicy define o uso de maiúsculas e minúsculas nos nomes das propriedades, de modo que JsonNamingPolicy.CamelCase transforma ReleaseDate em releaseDate. Definir DefaultIgnoreCondition como JsonIgnoreCondition.WhenWritingNull remove da saída as propriedades com valor null. Encoder controla como os caracteres são escapados, o que importa para conteúdo que não é seguro em HTML. Converters guarda as instâncias de JsonConverter que tratam os tipos que o comportamento padrão serializa errado, como um formato de data personalizado. WriteIndented adiciona quebras de linha e indentação, o que é útil em desenvolvimento e um desperdício em produção.
No ASP.NET Core, raramente criamos esse objeto nós mesmos. O framework mantém uma instância por pipeline e a entrega aos formatadores que escrevem as respostas. Por isso, definir opções globalmente significa recorrer ao objeto de opções do framework, e não a um JsonSerializerOptions que instanciamos com new em um controlador.
Quatro dessas cinco merecem uma análise mais detalhada.
Definir DefaultIgnoreCondition como JsonIgnoreCondition.WhenWritingNull não serve apenas para deixar a saída mais limpa: omitir propriedades com valor null reduz o tamanho do payload e pode melhorar o desempenho.
A propriedade Encoder ajuda a evitar ataques XSS ao codificar corretamente os dados JSON, normalmente com JavaScriptEncoder.Default.
A propriedade Converters é uma lista de instâncias de JsonConverter que usamos para personalizar a serialização de certos tipos que, por padrão, não são serializados como esperado. Isso é útil para tipos como DateTime ou objetos de negócio personalizados.
A propriedade WriteIndented formata a saída JSON com indentação e quebras de linha, o que a torna mais legível. Embora essa propriedade ajude na legibilidade durante o desenvolvimento, normalmente a desativamos em produção para reduzir o tamanho do payload.
Qual é o serializador JSON padrão no ASP.NET Core?
Por padrão, o ASP.NET Core usa o System.Text.Json. É assim desde o ASP.NET Core 3.0 e continua assim no .NET 10, em que um projeto dotnet new webapi recém-criado serializa com ele e não instala nenhum pacote JSON.
Antes disso, o padrão era o Newtonsoft.Json. O ASP.NET Web API 2 no .NET Framework serializava com o Json.NET, assim como o ASP.NET Core 1.x e 2.x, que o traziam pelos pacotes do MVC. É por isso que tanto código de exemplo antigo e tantas respostas antigas do Stack Overflow presumem que ele está em uso. Nada disso vale para um projeto criado hoje.
O Newtonsoft.Json continua com suporte completo, mas precisa ser ativado explicitamente. Instalar o pacote Microsoft.AspNetCore.Mvc.NewtonsoftJson e chamar AddNewtonsoftJson() em AddControllers() faz os formatadores de entrada e de saída voltarem para o Json.NET.
O serializador ativo determina qual objeto de opções configuramos. O System.Text.Json lê JsonSerializerOptions; o Newtonsoft.Json lê JsonSerializerSettings. Definir propriedades no objeto errado é o motivo mais comum para uma mudança global parecer não ter efeito nenhum.
| Framework | Serializador JSON padrão | Como alterar |
|---|---|---|
| ASP.NET Web API 2 (.NET Framework) | Newtonsoft.Json (Json.NET) | Substituir o JsonMediaTypeFormatter |
| ASP.NET Core 1.x a 2.x | Newtonsoft.Json (Json.NET), uma dependência do MVC | AddJsonOptions() em AddMvc() |
| ASP.NET Core 3.0 ao .NET 10 | System.Text.Json | AddJsonOptions(), ou AddNewtonsoftJson() para voltar ao Json.NET |
Se a biblioteca em si é novidade para nós, vale a pena começar por uma introdução ao System.Text.Json com exemplos antes de definir qualquer coisa globalmente.
Como definir opções JSON globais para controladores?
As ações de controlador leem a configuração JSON de Microsoft.AspNetCore.Mvc.JsonOptions. Ao definir essas opções uma única vez na inicialização, garantimos um tratamento uniforme dos dados JSON em todas as ações da aplicação.
Para começar, vamos criar uma classe Product no projeto Web API que geramos com dotnet new webapi --use-controllers:
public class Product
{
public int Id { get; set; }
public string? Name { get; set; }
public decimal Price { get; set; }
public int Quantity { get; set; }
public DateTime ReleaseDate { get; set; }
public Manufacturer Manufacturer { get; set; } = new Manufacturer();
}
Vamos criar também uma classe Manufacturer:
public class Manufacturer
{
public string? Name { get; set; }
public string? Location { get; set; }
}
Aqui, definimos duas classes de modelo para guardar as propriedades do produto.
Agora, vamos adicionar using System.Text.Encodings.Web;, using System.Text.Json; e using System.Text.Json.Serialization; no início do Program.cs e configurar as opções de serialização JSON na classe Program:
builder.Services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
options.JsonSerializerOptions.WriteIndented = false;
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Default;
options.JsonSerializerOptions.AllowTrailingCommas = true;
options.JsonSerializerOptions.NumberHandling = JsonNumberHandling.AllowReadingFromString;
});
Aqui, encadeamos AddJsonOptions() a AddControllers(), o que configura Microsoft.AspNetCore.Mvc.JsonOptions, o objeto de opções que o MVC entrega aos próprios formatadores.

E-book gratuito
Sua Web API está pronta para produção?
33 itens para verificar antes de implantá-la, com a correção de cada um. Um PDF gratuito de 76 páginas para .NET 10.
O e-book está em inglês.
Baixe o checklist gratuitoPDF gratuito. Um único e-mail para enviá-lo. Cancele a inscrição quando quiser.
builder.Services.Configure<JsonOptions>() chega ao mesmo objeto, mas só quando o tipo JsonOptions certo está no escopo, e qual deles está no escopo depende da diretiva using no início do arquivo. A forma encadeada deixa claro qual objeto de opções ela configura e, por isso, é preferível.
Primeiro, definimos todas as propriedades essenciais. Além disso, definimos AllowTrailingCommas para deixar o analisador mais flexível. Em seguida, definimos NumberHandling como JsonNumberHandling.AllowReadingFromString, que o ASP.NET Core já usa por padrão, para permitir que números escritos como strings JSON sejam convertidos nos tipos numéricos adequados.
Como uma das configurações aqui decide o uso de maiúsculas e minúsculas em todas as respostas que a API envia, vale a pena ler como a serialização de nomes de propriedades em camelCase se comporta em um projeto inteiro e como, ao escrever uma política de nomenclatura personalizada, estendemos isso a uma convenção que o framework não traz.
Agora, vamos criar uma classe ProductController e definir um método POST:
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class ProductController : ControllerBase
{
[HttpPost]
public ActionResult CreateProduct(Product product)
{
return Ok(product);
}
}
Aqui, criamos um método POST simples, que recebe o objeto Product como parâmetro de entrada e o retorna sem nenhuma modificação.
Vejamos os dados JSON do produto que enviamos à API no corpo da requisição:
{
"Id": 1,
"Name": null,
"Price": 0,
"Quantity": "5",
"ReleaseDate": "2024-04-14T10:49:31.813Z",
"Manufacturer": {
"Name":"Apple",
"Location" : "California"
}
}
Escrevemos os nomes das propriedades JSON em PascalCase. Além disso, definimos a propriedade Name como null e passamos a propriedade Quantity no formato de string.
Agora, vamos examinar a resposta, indentada aqui para facilitar a leitura:
{
"id": 1,
"price": 0,
"quantity": 5,
"releaseDate": "2024-04-14T10:49:31.813Z",
"manufacturer": {
"name": "Apple",
"location": "California"
}
}
O serializador JSON passa os nomes de PascalCase para camelCase e exclui a propriedade Name por causa da nossa configuração de JsonIgnoreCondition.WhenWritingNull.
A propriedade NumberHandling interpreta Quantity como número, apesar do formato de string, e AllowTrailingCommas permite que o analisador aceite uma vírgula final no payload em vez de rejeitá-la.
Como definir opções JSON globais para APIs mínimas?
Quando criamos APIs mínimas, é essencial ter um controle refinado das configurações de serialização JSON especificamente para requisições e respostas HTTP. Isso significa aplicar configurações de serialização JSON específicas exclusivamente ao JSON que os nossos endpoints recebem dos clientes e enviam de volta a eles.
O método de extensão ConfigureHttpJsonOptions() nos permite personalizar opções JSON que se aplicam exclusivamente ao pipeline HTTP, garantindo que essas configurações fiquem isoladas de outras partes da aplicação.
Seguindo em frente, vamos configurar o método ConfigureHttpJsonOptions() na classe Program:
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
options.SerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
options.SerializerOptions.WriteIndented = false;
options.SerializerOptions.Encoder = JavaScriptEncoder.Default;
options.SerializerOptions.AllowTrailingCommas = true;
options.SerializerOptions.NumberHandling = JsonNumberHandling.AllowReadingFromString;
});
Aqui, adicionamos o método ConfigureHttpJsonOptions() ao IServiceCollection. Da mesma forma, definimos as propriedades de serialização JSON como fizemos antes.
A documentação de APIs mínimas da Microsoft diz isso em uma linha: “As opções podem ser configuradas globalmente para uma aplicação com uma chamada a ConfigureHttpJsonOptions.”
Em seguida, vamos definir uma API mínima na classe Program:
app.MapPost("api/Product/create", (Product product) =>
{
return product;
});
As configurações de serialização que definimos serão aplicadas a essa resposta.
Como usar o Newtonsoft.Json globalmente no ASP.NET Core?
Dois passos fazem do Newtonsoft.Json o serializador de todos os controladores. Instale o pacote Microsoft.AspNetCore.Mvc.NewtonsoftJson e depois encadeie AddNewtonsoftJson() a AddControllers(), definindo em options.SerializerSettings as propriedades desejadas.
Essa única chamada substitui os formatadores de entrada e de saída do MVC. A partir daí, todas as ações de controlador serializam e desserializam com o Json.NET, sem nenhuma mudança nas próprias ações e sem nenhuma chamada a JsonConvert no nosso código.
JsonConvert.DefaultSettings é outra coisa, e confundir os dois é um erro comum. Ele afeta as chamadas diretas a JsonConvert.SerializeObject() e JsonConvert.DeserializeObject() que nós mesmos escrevemos. Uma ação que retorna um objeto continua passando pelo formatador que o MVC tiver registrado, então definir apenas DefaultSettings não muda nada na resposta que o cliente recebe.
Recorra ao Newtonsoft.Json quando precisar do que ele ainda faz melhor: DateFormatString, DefaultValueHandling e um ecossistema de conversores construído ao longo de uma década de uso.
O Newtonsoft.Json, também chamado de Json.NET, nos dá mais opções para formatar datas e tratar valores null do que o System.Text.Json. Por exemplo, ele consegue serializar datas como strings em vários formatos e tratar valores null de várias maneiras (ignorar, incluir ou rejeitar).
Como primeiro passo, vamos instalar o pacote Microsoft.AspNetCore.Mvc.NewtonsoftJson:
dotnet add package Microsoft.AspNetCore.Mvc.NewtonsoftJson

E-book gratuito
Sua Web API está pronta para produção?
33 itens para verificar antes de implantá-la, com a correção de cada um. Um PDF gratuito de 76 páginas para .NET 10.
O e-book está em inglês.
Baixe o checklist gratuitoPDF gratuito. Um único e-mail para enviá-lo. Cancele a inscrição quando quiser.
Com using Newtonsoft.Json; e using Newtonsoft.Json.Serialization; no início do Program.cs, vamos registrar o Json.NET para todos os controladores na classe Program:
builder.Services.AddControllers()
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
options.SerializerSettings.Formatting = Formatting.Indented;
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
options.SerializerSettings.DateFormatString = "dd-MM-yyyy";
options.SerializerSettings.DefaultValueHandling = DefaultValueHandling.Ignore;
});
Em seguida, definimos camelCase como a estratégia de nomenclatura padrão das chaves JSON, usando CamelCasePropertyNamesContractResolver(). Também formatamos o JSON de saída com indentação, para facilitar a leitura. Depois, omitimos do JSON resultante as propriedades do objeto com valor null e serializamos as datas como strings no formato “dia-mês-ano”.
Por fim, definimos o tratamento de valores padrão das propriedades como DefaultValueHandling.Ignore, o que faz com que as propriedades com valores padrão (como 0 para inteiros, false para booleanos etc.) fiquem fora da serialização.
Essa única chamada é exclusiva: ela troca os dois formatadores do MVC, então as opções do System.Text.Json que definimos antes deixam de valer para as ações de controlador assim que ela é registrada.
Vamos definir um endpoint POST na classe ProductController:
[HttpPost("save")]
public ActionResult SaveProduct(Product product)
{
return Ok(product);
}
Nessa ação, retornamos o objeto product e deixamos que o formatador registrado o serialize. Não há nenhuma chamada a JsonConvert em lugar nenhum, e é justamente esse o objetivo de configurar o serializador globalmente.
Então, vamos ver o corpo da requisição:
{
"Id": 1,
"Name": null,
"Price": 0,
"Quantity":"5",
"ReleaseDate": "2024-04-14T10:49:31.813Z",
"Manufacturer":
{
"Name":"Apple",
"Location" : "California"
}
}
Incluímos propriedades JSON com nomes em PascalCase e valores padrão nas propriedades Name e Price.
Vamos conferir a resposta:
{
"id": 1,
"quantity": 5,
"releaseDate": "14-04-2024",
"manufacturer": {
"name": "Apple",
"location": "California"
}
}
A propriedade Name fica fora da resposta porque contém um valor null. A serialização formata a propriedade ReleaseDate no estilo ‘dd-MM-yyyy’, e a propriedade Price é ignorada porque a definimos com o valor padrão 0.
Qual objeto de opções JSON vale para quais endpoints?
O ASP.NET Core tem dois objetos de opções JSON separados e, o que gera confusão, os dois tipos se chamam JsonOptions.
Microsoft.AspNetCore.Mvc.JsonOptions atende às ações de controlador e expõe a configuração por meio de uma propriedade chamada JsonSerializerOptions. Microsoft.AspNetCore.Http.Json.JsonOptions atende aos endpoints de APIs mínimas, ao Results.Json() e ao TypedResults, e expõe a configuração por meio de uma propriedade chamada SerializerOptions. Uma chamada Configure<JsonOptions>() não qualificada alcança um dos dois, e qual deles depende inteiramente da diretiva using no início do arquivo.
Os dois não se propagam um para o outro. Configurar um deixa o outro com os valores padrão. Por isso, uma política de nomenclatura definida com AddJsonOptions() muda o que um controlador retorna e nunca chega aos endpoints de APIs mínimas, e ConfigureHttpJsonOptions() muda o que um endpoint de API mínima retorna e nunca chega aos formatadores do MVC. Uma aplicação que atende aos dois tipos de endpoint precisa configurar os dois.
As nossas próprias chamadas a JsonSerializer.Serialize() não leem nenhum dos dois objetos. Elas usam a instância de opções que passamos a elas, ou os padrões da biblioteca quando não passamos nenhuma, e é por isso que uma mudança global nunca as alcança.
Qual formatador chega a rodar é decidido um passo antes, quando a negociação de conteúdo escolhe o formatador da requisição.
Boas práticas e considerações
Quando atualizamos as configurações de serialização JSON globalmente, é essencial avaliar com cuidado os possíveis efeitos sobre a base de código existente, para evitar consequências indesejadas. Isso pode alterar o comportamento de endpoints da API que os clientes já consomem, o que pode quebrar contratos se os clientes dependerem do formato de serialização atual. Devemos implementar as mudanças de forma gradual, com testes abrangentes e chaves de ativação de recursos (feature toggles), que podem ajudar a evitar interrupções no comportamento do sistema.
A consistência é fundamental nas práticas de serialização JSON de uma aplicação. Ela facilita o entendimento e ajuda a evitar bugs. Precisamos centralizar e documentar as configurações de serialização para contar com um comportamento uniforme em toda a aplicação. Os dois tipos JsonOptions são classes de opções comuns, então o padrão de opções que esses objetos de configuração usam se aplica a eles como a qualquer outra classe de opções.
Quando os dados serializados fazem parte de um contrato com sistemas externos ou precisam ser armazenados por muito tempo, garantir compatibilidade e um versionamento cuidadoso é crucial. Devemos introduzir as mudanças por meio de APIs versionadas e considerar o impacto sobre o armazenamento e o processamento dos dados e sobre os consumidores externos. Essa abordagem estratégica vai preservar a integridade dos dados e permitir que a base de código evolua sem sobressaltos à medida que surgem novas boas práticas. Para alguns consumidores, a ordem das propriedades faz parte desse contrato, e controlar a ordem em que as propriedades são escritas é outra questão de JsonSerializerOptions que vale a pena resolver de uma vez.
Pensando no futuro do .NET, precisamos levar em conta estes fatores adicionais. O System.Text.Json da Microsoft é o serializador padrão das novas aplicações .NET. Mesmo que optemos por usar o Newtonsoft.Json, devemos ficar atentos a possíveis mudanças nas boas práticas e estar preparados para adaptar a nossa estratégia à medida que o ecossistema evolui.
Conclusão
Neste artigo, vimos diferentes formas de definir as configurações de serialização JSON no ASP.NET Core, incluindo as opções nativas do System.Text.Json e os recursos mais abrangentes do Newtonsoft.Json.
Testado com .NET 10.0.10 (SDK 10.0.302), Newtonsoft.Json 13.0.4 e Microsoft.AspNetCore.Mvc.NewtonsoftJson 10.0.11.