Migrar de Newtonsoft.Json para System.Text.Json
Este artigo mostra como migrar do Newtonsoft.Json .System.Text.Json
O System.Text.Json
namespace fornece funcionalidade para serializar e desserializar a partir de JavaScript Object Notation (JSON). A System.Text.Json
biblioteca está incluída no tempo de execução do .NET Core 3.1 e versões posteriores. Para outras estruturas de destino, instale o System.Text.Json pacote NuGet. O pacote suporta:
- .NET Standard 2.0 e versões posteriores
- .NET Framework 4.6.2 e versões posteriores
- .NET Core 2.0, 2.1 e 2.2
Gorjeta
Você pode usar a assistência de IA para migrar com Newtonsoft.Json
o GitHub Copilot.
System.Text.Json
Concentra-se principalmente no desempenho, segurança e conformidade com as normas. Ele tem algumas diferenças importantes no comportamento padrão e não visa ter paridade de recursos com Newtonsoft.Json
o . Para alguns cenários, System.Text.Json
atualmente não tem funcionalidade interna, mas há soluções alternativas recomendadas. Para outros cenários, as soluções alternativas são impraticáveis.
A System.Text.Json
equipe está investindo na adição dos recursos que são mais solicitados. Se seu aplicativo depender de um recurso ausente, considere arquivar um problema no repositório GitHub dotnet/runtime para descobrir se o suporte para seu cenário pode ser adicionado.
A maior parte deste artigo é sobre como usar a JsonSerializer API, mas também inclui orientações sobre como usar o JsonDocument (que representa o Document Object Model ou DOM) Utf8JsonReadere Utf8JsonWriter tipos.
No Visual Basic, você não pode usar Utf8JsonReader, o que também significa que você não pode escrever conversores personalizados. A maioria das soluções alternativas apresentadas aqui requer que você escreva conversores personalizados. Você pode escrever um conversor personalizado em C# e registrá-lo em um projeto Visual Basic. Para obter mais informações, consulte Suporte do Visual Basic.
Tabela de diferenças
A tabela a seguir lista Newtonsoft.Json
recursos e System.Text.Json
equivalentes. Os equivalentes enquadram-se nas seguintes categorias:
- ✔️ Suportado pela funcionalidade integrada. Obter um comportamento semelhante pode exigir o uso de
System.Text.Json
um atributo ou opção global. -
⚠️ Não suportado, mas a solução alternativa é possível. As soluções alternativas são conversores personalizados, que podem não fornecer paridade completa com
Newtonsoft.Json
a funcionalidade. Para alguns deles, o código de exemplo é fornecido como exemplos. Se você confiar nessesNewtonsoft.Json
recursos, a migração exigirá modificações em seus modelos de objeto .NET ou outras alterações de código. -
❌ Não suportado e a solução alternativa não é prática ou possível. Se você confiar nesses
Newtonsoft.Json
recursos, a migração não será possível sem alterações significativas.
Funcionalidade do Newtonsoft.Json | System.Text.Json equivalente |
---|---|
Desserialização sem diferenciação de maiúsculas e minúsculas por padrão | ✔️ Configuração global PropertyNameCaseInsensitive |
Nomes de propriedades camel-case | ✔️ Configuração global de PropertyNamingPolicy |
Nomes de propriedade de caso de cobra | ✔️ Política de nomenclatura de casos de cobra |
Fuga mínima de caracteres | ✔️ Fuga estrita de caracteres, configurável |
NullValueHandling.Ignore cenário global |
✔️ Opção global DefaultIgnoreCondition |
Permitir comentários | ✔️ ReadCommentManipulando a configuração global |
Permitir vírgulas à direita | ✔️ Configuração global AllowTrailingCommas |
Registo personalizado do conversor | ✔️ A ordem de precedência difere |
Profundidade máxima padrão 64, configurável | ✔️ Profundidade máxima padrão 64, configurável |
PreserveReferencesHandling cenário global |
✔️ Configuração global ReferenceHandling |
Serializar ou desserializar números entre aspas | ✔️ Configuração global NumberHanding, atributo [JsonNumberHandling] |
Desserializar para classes e estruturas imutáveis | ✔️ JsonConstructor, C# 9 Registros |
Suporte para campos | ✔️ Configuração global IncludeFields, atributo [JsonInclude] |
DefaultValueHandling cenário global |
✔️ Configuração global DefaultIgnoreCondition |
NullValueHandling configuração em [JsonProperty] |
✔️ Atributo JsonIgnore |
DefaultValueHandling configuração em [JsonProperty] |
✔️ Atributo JsonIgnore |
Desserializar Dictionary com chave não-string |
✔️ Suportado |
Apoio a criadores e arrendatários de propriedades não públicas | ✔️ Atributo JsonInclude |
Atributo [JsonConstructor] |
✔️ Atributo [JsonConstructor] |
ReferenceLoopHandling cenário global |
✔️ Configuração global ReferenceHandling |
Chamadas de retorno | ✔️ Retornos de chamada |
NaN, Infinito, -Infinito | ✔️ Suportado |
Required configuração no [JsonProperty] atributo |
✔️ Atributo [JsonRequired] e modificador necessário em C# |
DefaultContractResolver Para ignorar propriedades |
✔️ DefaultJsonTypeInfoResolver classe |
Serialização polimórfica | ✔️ Atributo [JsonDerivedType] |
Desserialização polimórfica | ✔️ Discriminador de tipo no atributo [JsonDerivedType] |
Desserializar o valor do enum da cadeia de caracteres | ✔️ Desserializar valores de enum de cadeia de caracteres |
MissingMemberHandling cenário global |
✔️ Lidar com membros ausentes |
Preencher propriedades sem setters | ✔️ Preencher propriedades sem setters |
ObjectCreationHandling cenário global |
✔️ Reutilizar em vez de substituir propriedades |
Suporte para uma ampla gama de tipos | ⚠ ️ Alguns tipos requerem conversores personalizados |
Desserializar o tipo inferido para object propriedades |
⚠ ️ Não suportado, solução alternativa, amostra |
Desserializar JSON null literal para tipos de valor não anuláveis |
⚠ ️ Não suportado, solução alternativa, amostra |
DateTimeZoneHandling , DateFormatString configurações |
⚠ ️ Não suportado, solução alternativa, amostra |
JsonConvert.PopulateObject método |
⚠ ️ Não suportado, solução alternativa |
Suporte para System.Runtime.Serialization atributos |
⚠ ️ Não suportado, solução alternativa, amostra |
JsonObjectAttribute |
⚠ ️ Não suportado, solução alternativa |
Permitir nomes de propriedades sem aspas | ❌ Não suportado pelo design |
Permitir aspas simples em torno de valores de cadeia de caracteres | ❌ Não suportado pelo design |
Permitir valores JSON sem cadeia de caracteres para propriedades de cadeia de caracteres | ❌ Não suportado pelo design |
TypeNameHandling.All cenário global |
❌ Não suportado pelo design |
Suporte para JsonPath consultas |
❌ Não suportado |
Limites configuráveis | ❌ Não suportado |
Esta não é uma lista exaustiva de Newtonsoft.Json
características. A lista inclui muitos dos cenários que foram solicitados em problemas do GitHub ou postagens do StackOverflow. Se você implementar uma solução alternativa para um dos cenários listados aqui que atualmente não tem código de exemplo e se quiser compartilhar sua solução, selecione Esta página na seção Comentários na parte inferior desta página. Isso cria um problema no repositório GitHub desta documentação e o lista na seção Comentários desta página também.
Diferenças no comportamento padrão
System.Text.Json é rigoroso por padrão e evita qualquer adivinhação ou interpretação em nome do chamador, enfatizando o comportamento determinista. A biblioteca é intencionalmente projetada desta forma para desempenho e segurança.
Newtonsoft.Json
é flexível por padrão. Essa diferença fundamental no design está por trás de muitas das seguintes diferenças específicas no comportamento padrão.
Desserialização sem diferenciação de maiúsculas e minúsculas
Durante a desserialização, Newtonsoft.Json
faz a correspondência de nome de propriedade sem diferenciação de maiúsculas e minúsculas por padrão. O System.Text.Json padrão diferencia maiúsculas de minúsculas, o que proporciona um melhor desempenho, uma vez que está fazendo uma correspondência exata. Para obter informações sobre como fazer a correspondência que não diferencia maiúsculas de minúsculas, consulte Correspondência de propriedade que não diferencia maiúsculas de minúsculas.
Se você estiver usando System.Text.Json
indiretamente usando o ASP.NET Core, não precisará fazer nada para obter um comportamento como Newtonsoft.Json
o . ASP.NET Core especifica as configurações para nomes de propriedades de caixa camel e correspondência sem diferenciação de maiúsculas e minúsculas quando usa System.Text.Json
.
ASP.NET Core também permite a desserialização de números cotados por padrão.
Fuga mínima de caracteres
Durante a serialização, Newtonsoft.Json
é relativamente permissivo em deixar os personagens passarem sem escapar deles. Ou seja, não os substitui por \uxxxx
onde xxxx
está o ponto de código do personagem. Onde ele escapa deles, ele o faz emitindo um \
antes do personagem (por exemplo, "
torna-se \"
).
System.Text.Json escapa de mais caracteres por padrão para fornecer proteções de defesa profunda contra scripts entre sites (XSS) ou ataques de divulgação de informações e faz isso usando a sequência de seis caracteres.
System.Text.Json
escapa de todos os caracteres não-ASCII por padrão, portanto, você não precisa fazer nada se estiver usando StringEscapeHandling.EscapeNonAscii
o Newtonsoft.Json
.
System.Text.Json
também escapa de caracteres sensíveis a HTML, por padrão. Para obter informações sobre como substituir o comportamento padrão System.Text.Json
, consulte Personalizar codificação de caracteres.
Comentários
Durante a desserialização, Newtonsoft.Json
ignora comentários no JSON por padrão. O System.Text.Json padrão é lançar exceções para comentários porque a especificação RFC 8259 não os inclui. Para obter informações sobre como permitir comentários, consulte Permitir comentários e vírgulas à direita.
Vírgulas à direita
Durante a desserialização, Newtonsoft.Json
ignora vírgulas à direita por padrão. Ele também ignora várias vírgulas à direita (por exemplo, [{"Color":"Red"},{"Color":"Green"},,]
). O System.Text.Json padrão é lançar exceções para vírgulas à direita porque a especificação RFC 8259 não as permite. Para obter informações sobre como fazer System.Text.Json
com que sejam aceites, consulte Permitir comentários e vírgulas à direita. Não há como permitir várias vírgulas à direita.
Precedência de registro do conversor
A Newtonsoft.Json
precedência de registro para conversores personalizados é a seguinte:
- Atributo na propriedade
- Atributo no tipo
- Coleção de conversores
Essa ordem significa que um conversor personalizado na Converters
coleção é substituído por um conversor que é registrado aplicando um atributo no nível do tipo. Ambos os registros são substituídos por um atributo no nível da propriedade.
A System.Text.Json precedência de registro para conversores personalizados é diferente:
- Atributo na propriedade
- Converters Coleção
- Atributo no tipo
A diferença aqui é que um conversor personalizado na Converters
coleção substitui um atributo no nível do tipo. A intenção por trás dessa ordem de precedência é fazer com que as alterações em tempo de execução substituam as escolhas de tempo de design. Não há como alterar a precedência.
Para obter mais informações sobre o registro do conversor personalizado, consulte Registrar um conversor personalizado.
Profundidade máxima
A versão mais recente do Newtonsoft.Json
tem um limite máximo de profundidade de 64 por padrão.
System.Text.Json também tem um limite padrão de 64 e é configurável pela configuração JsonSerializerOptions.MaxDepth.
Se você estiver usando System.Text.Json
indiretamente usando o ASP.NET Core, o limite máximo de profundidade padrão é 32. O valor padrão é o mesmo que para a vinculação de modelo e é definido na classe JsonOptions.
Cadeias de caracteres JSON (nomes de propriedades e valores de cadeia de caracteres)
Durante a desserialização, Newtonsoft.Json
aceita nomes de propriedades entre aspas duplas, aspas simples ou sem aspas. Ele aceita valores de cadeia de caracteres cercados por aspas duplas ou aspas simples. Por exemplo, Newtonsoft.Json
aceita o seguinte JSON:
{
"name1": "value",
'name2': "value",
name3: 'value'
}
System.Text.Json
só aceita nomes de propriedade e valores de cadeia de caracteres entre aspas duplas porque esse formato é exigido pela especificação RFC 8259 e é o único formato considerado JSON válido.
Um valor entre aspas simples resulta em um JsonException com a seguinte mensagem:
''' is an invalid start of a value.
Valores sem cadeia de caracteres para propriedades de cadeia de caracteres
Newtonsoft.Json
Aceita valores que não sejam de cadeia de caracteres, como um número ou os literais true
e false
, para desserialização para propriedades do tipo string. Aqui está um exemplo de JSON que Newtonsoft.Json
desserializa com êxito para a seguinte classe:
{
"String1": 1,
"String2": true,
"String3": false
}
public class ExampleClass
{
public string String1 { get; set; }
public string String2 { get; set; }
public string String3 { get; set; }
}
System.Text.Json
não desserializa valores que não sejam de cadeia de caracteres em propriedades de cadeia de caracteres. Um valor não-string recebido para um campo de cadeia de caracteres resulta em um JsonException com a seguinte mensagem:
The JSON value could not be converted to System.String.
Cenários usando JsonSerializer
Alguns dos cenários a seguir não são suportados pela funcionalidade interna, mas soluções alternativas são possíveis. As soluções alternativas são conversores personalizados, que podem não fornecer paridade completa com Newtonsoft.Json
a funcionalidade. Para alguns deles, o código de exemplo é fornecido como exemplos. Se você confiar nesses Newtonsoft.Json
recursos, a migração exigirá modificações em seus modelos de objeto .NET ou outras alterações de código.
Para alguns dos cenários a seguir, as soluções alternativas não são práticas ou possíveis. Se você confiar nesses Newtonsoft.Json
recursos, a migração não será possível sem alterações significativas.
Permitir ou escrever números entre aspas
Newtonsoft.Json
pode serializar ou desserializar números representados por cadeias de caracteres JSON (cercadas por aspas). Por exemplo, pode aceitar: {"DegreesCelsius":"23"}
em vez de {"DegreesCelsius":23}
. Para habilitar esse comportamento em System.Text.Json, defina JsonSerializerOptions.NumberHandling como WriteAsString ou AllowReadingFromStringou use o atributo [JsonNumberHandling].
Se você estiver usando System.Text.Json
indiretamente usando o ASP.NET Core, não precisará fazer nada para obter um comportamento como Newtonsoft.Json
o . ASP.NET Core especifica os padrões da Web quando usa System.Text.Json
o , e os padrões da Web permitem números entre aspas.
Para obter mais informações, consulte Permitir ou escrever números entre aspas.
Especifique o construtor a ser usado ao desserializar
O Newtonsoft.Json
[JsonConstructor]
atributo permite especificar qual construtor chamar ao desserializar para um POCO.
System.Text.Json
também tem um atributo [JsonConstructor]. Para obter mais informações, consulte Tipos e registros imutáveis.
Ignorar condicionalmente uma propriedade
Newtonsoft.Json
tem várias maneiras de ignorar condicionalmente uma propriedade na serialização ou desserialização:
-
DefaultContractResolver
Permite selecionar propriedades a serem incluídas ou ignoradas, com base em critérios arbitrários. - As
NullValueHandling
configurações eDefaultValueHandling
emJsonSerializerSettings
permitem especificar que todas as propriedades de valor nulo ou valor padrão devem ser ignoradas. - As
NullValueHandling
configurações eDefaultValueHandling
no[JsonProperty]
atributo permitem especificar propriedades individuais que devem ser ignoradas quando definidas como null ou o valor padrão.
System.Text.Json Fornece as seguintes maneiras de ignorar propriedades ou campos durante a serialização:
- O atributo [JsonIgnore] em uma propriedade faz com que a propriedade seja omitida do JSON durante a serialização.
- A opção global IgnoreReadOnlyProperties permite ignorar todas as propriedades somente leitura.
- Se você estiver incluindo campos, a JsonSerializerOptions.IgnoreReadOnlyFields opção global permite ignorar todos os campos somente leitura.
- A
DefaultIgnoreCondition
opção global permite ignorar todas as propriedades de tipo de valor que têm valores padrão ou ignorar todas as propriedades de tipo de referência que têm valores nulos.
Além disso, no .NET 7 e versões posteriores, você pode personalizar o contrato JSON para ignorar propriedades com base em critérios arbitrários. Para obter mais informações, consulte Contratos personalizados.
Domínios públicos e não públicos
Newtonsoft.Json
pode serializar e desserializar campos, bem como propriedades.
No System.Text.Json, use a JsonSerializerOptions.IncludeFields configuração global ou o atributo [JsonInclude] para incluir campos públicos ao serializar ou desserializar. Para obter um exemplo, consulte Incluir campos.
Preservar referências de objeto e manipular loops
Por padrão, Newtonsoft.Json
serializa por valor. Por exemplo, se um objeto contiver duas propriedades que contenham uma referência ao mesmo Person
objeto, os valores das propriedades desse Person
objeto serão duplicados no JSON.
Newtonsoft.Json
tem uma PreserveReferencesHandling
configuração que JsonSerializerSettings
permite serializar por referência:
- Um metadados de identificador é adicionado ao JSON criado para o primeiro
Person
objeto. - O JSON criado para o segundo
Person
objeto contém uma referência a esse identificador em vez de valores de propriedade.
Newtonsoft.Json
também tem uma ReferenceLoopHandling
configuração que permite ignorar referências circulares em vez de lançar uma exceção.
Para preservar referências e manipular referências circulares em System.Text.Json, defina JsonSerializerOptions.ReferenceHandler como Preserve. A ReferenceHandler.Preserve
configuração é equivalente a PreserveReferencesHandling
= PreserveReferencesHandling.All
em Newtonsoft.Json
.
A ReferenceHandler.IgnoreCycles
opção tem comportamento semelhante ao Newtonsoft.JsonReferenceLoopHandling.Ignore
. Uma diferença é que a System.Text.Json implementação substitui loops de referência pelo null
token JSON em vez de ignorar a referência de objeto. Para obter mais informações, consulte Ignorar referências circulares.
Como o Newtonsoft.JsonReferenceResolver, a System.Text.Json.Serialization.ReferenceResolver classe define o comportamento de preservar referências na serialização e desserialização. Crie uma classe derivada para especificar o comportamento personalizado. Para obter um exemplo, consulte GuidReferenceResolver.
Alguns recursos relacionados Newtonsoft.Json
não são suportados:
Para obter mais informações, consulte Preservar referências e manipular referências circulares.
Dicionário com chave não-string
Ambos Newtonsoft.Json
e System.Text.Json
apoiar coleções do tipo Dictionary<TKey, TValue>
. Para obter informações sobre os tipos de chave suportados, consulte Tipos de chave suportados.
Atenção
Desserializar para um Dictionary<TKey, TValue>
onde TKey
é digitado como qualquer coisa diferente de string
poderia introduzir uma vulnerabilidade de segurança no aplicativo consumidor. Para obter mais informações, consulte dotnet/runtime#4761.
Tipos sem suporte integrado
System.Text.Json não fornece suporte interno para os seguintes tipos:
- DataTable e tipos relacionados (para obter mais informações, consulte Tipos suportados)
- ExpandoObject
- TimeZoneInfo
- BigInteger
- DBNull
- Type
- ValueTuple e os tipos genéricos que lhe estão associados
Conversores personalizados podem ser implementados para tipos que não têm suporte interno.
Serialização polimórfica
Newtonsoft.Json
Automaticamente faz serialização polimórfica. A partir do .NET 7, System.Text.Json oferece suporte à serialização polimórfica por meio do JsonDerivedTypeAttribute atributo. Para obter mais informações, consulte Serializar propriedades de classes derivadas.
Desserialização polimórfica
Newtonsoft.Json
tem uma TypeNameHandling
configuração que adiciona metadados de nome de tipo ao JSON durante a serialização. Ele usa os metadados durante a desserialização para fazer a desserialização polimórfica. A partir do .NET 7, System.Text.Json depende das informações do discriminador de tipo para executar a desserialização polimórfica. Esses metadados são emitidos no JSON e, em seguida, usados durante a desserialização para determinar se a desserialização deve ser desserializada para o tipo base ou um tipo derivado. Para obter mais informações, consulte Serializar propriedades de classes derivadas.
Para oferecer suporte à desserialização polimórfica em versões mais antigas do .NET, crie um conversor como o exemplo em Como escrever conversores personalizados.
Desserializar valores de enum de cadeia de caracteres
Por padrão, System.Text.Json não oferece suporte à desserialização de valores de enum de cadeia de caracteres, enquanto Newtonsoft.Json
oferece. Por exemplo, o código a seguir lança um JsonException:
string json = "{ \"Text\": \"Hello\", \"Enum\": \"Two\" }";
var _ = JsonSerializer.Deserialize<MyObj>(json); // Throws exception.
class MyObj
{
public string Text { get; set; } = "";
public MyEnum Enum { get; set; }
}
enum MyEnum
{
One,
Two,
Three
}
No entanto, você pode habilitar a desserialização de valores de enum de cadeia de caracteres usando o JsonStringEnumConverter conversor. Para obter mais informações, consulte Enums as strings.
Desserialização de propriedades de objeto
Quando Newtonsoft.Json
desserializa para Object, ele:
- Infere o tipo de valores primitivos na carga JSON (diferente de
null
) e retorna o armazenadostring
,long
,double
,boolean
, ouDateTime
como um objeto in a box. Os valores primitivos são valores JSON únicos, como um número JSON, cadeia de caracteres,true
,false
ounull
. - Retorna um
JObject
ouJArray
para valores complexos na carga JSON útil. Valores complexos são coleções de pares chave-valor JSON dentro de chaves ({}
) ou listas de valores entre colchetes ([]
). As propriedades e valores dentro das chaves ou colchetes podem ter propriedades ou valores adicionais. - Retorna uma referência nula quando a carga tem o
null
literal JSON.
System.Text.Json armazena JsonElement
uma caixa para valores primitivos e complexos sempre que desserializar para Object, por exemplo:
- Uma
object
propriedade. - Um valor de
object
dicionário. - Um
object
valor de matriz. - Uma raiz
object
.
No entanto, System.Text.Json
trata null
o mesmo que Newtonsoft.Json
e retorna uma referência nula quando a carga útil tem o null
literal JSON nela.
Para implementar a inferência de tipo para object
propriedades, crie um conversor como o exemplo em Como escrever conversores personalizados.
Desserializar nulo para tipo não anulável
Newtonsoft.Json
não lança uma exceção no seguinte cenário:
-
NullValueHandling
está definido comoIgnore
, e - Durante a desserialização, o JSON contém um valor nulo para um tipo de valor não anulável.
No mesmo cenário, System.Text.Json lança uma exceção. (A configuração de manipulação nula correspondente em System.Text.Json
é JsonSerializerOptions.IgnoreNullValues = true
.)
Se você possui o tipo de destino, a melhor solução é tornar a propriedade em questão anulável (por exemplo, alterar int
para int?
).
Outra solução é criar um conversor para o tipo, como o exemplo a seguir que manipula valores nulos para DateTimeOffset
tipos:
using System.Text.Json;
using System.Text.Json.Serialization;
namespace SystemTextJsonSamples
{
public class DateTimeOffsetNullHandlingConverter : JsonConverter<DateTimeOffset>
{
public override DateTimeOffset Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options) =>
reader.TokenType == JsonTokenType.Null
? default
: reader.GetDateTimeOffset();
public override void Write(
Utf8JsonWriter writer,
DateTimeOffset dateTimeValue,
JsonSerializerOptions options) =>
writer.WriteStringValue(dateTimeValue);
}
}
Registre esse conversor personalizado usando um atributo na propriedade ou adicionando o conversor à Converters coleção.
Nota: O conversor anterior manipula valores nulos de forma diferente do Newtonsoft.Json
que faz para POCOs que especificam valores padrão. Por exemplo, suponha que o código a seguir representa seu objeto de destino:
public class WeatherForecastWithDefault
{
public WeatherForecastWithDefault()
{
Date = DateTimeOffset.Parse("2001-01-01");
Summary = "No summary";
}
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string Summary { get; set; }
}
E suponha que o seguinte JSON é desserializado usando o conversor anterior:
{
"Date": null,
"TemperatureCelsius": 25,
"Summary": null
}
Após a desserialização, a Date
propriedade tem 1/1/0001 (default(DateTimeOffset)
), ou seja, o valor definido no construtor é substituído. Dado o mesmo POCO e JSON, Newtonsoft.Json
a Date
desserialização deixaria 1/1/2001 na propriedade.
Desserializar para classes e estruturas imutáveis
Newtonsoft.Json
pode desserializar para classes e estruturas imutáveis porque pode usar construtores que têm parâmetros.
Em System.Text.Json, use o atributo [JsonConstructor] para especificar o uso de um construtor parametrizado. Os registros em C# 9 também são imutáveis e são suportados como destinos de desserialização. Para obter mais informações, consulte Tipos e registros imutáveis.
Propriedades obrigatórias
No Newtonsoft.Json
, você especifica que uma propriedade é necessária definindo Required
no [JsonProperty]
atributo.
Newtonsoft.Json
lança uma exceção se nenhum valor for recebido no JSON para uma propriedade marcada como necessária.
A partir do .NET 7, você pode usar o modificador C# required
ou o JsonRequiredAttribute atributo em uma propriedade necessária.
System.Text.Json lança uma exceção se a carga JSON não contiver um valor para a propriedade marcada. Para obter mais informações, consulte Propriedades necessárias.
Especificar formato de data
Newtonsoft.Json
Fornece várias maneiras de controlar como as propriedades e DateTime
DateTimeOffset
os tipos são serializados e desserializados:
- A
DateTimeZoneHandling
configuração pode ser usada para serializar todos osDateTime
valores como datas UTC. - A
DateFormatString
configuração eDateTime
os conversores podem ser usados para personalizar o formato das cadeias de data.
System.Text.Json suporta ISO 8601-1:2019, incluindo o perfil RFC 3339. Este formato é amplamente adotado, inequívoco e faz viagens de ida e volta com precisão. Para usar qualquer outro formato, crie um conversor personalizado. Por exemplo, os seguintes conversores serializam e desserializam JSON que usa o formato de época Unix com ou sem um deslocamento de fuso horário (valores como /Date(1590863400000-0700)/
ou /Date(1590863400000)/
):
sealed class UnixEpochDateTimeOffsetConverter : JsonConverter<DateTimeOffset>
{
static readonly DateTimeOffset s_epoch = new(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
static readonly Regex s_regex = new("^/Date\\(([+-]*\\d+)([+-])(\\d{2})(\\d{2})\\)/$", RegexOptions.CultureInvariant);
public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
string formatted = reader.GetString()!;
Match match = s_regex.Match(formatted);
if (
!match.Success
|| !long.TryParse(match.Groups[1].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out long unixTime)
|| !int.TryParse(match.Groups[3].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out int hours)
|| !int.TryParse(match.Groups[4].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out int minutes))
{
throw new JsonException();
}
int sign = match.Groups[2].Value[0] == '+' ? 1 : -1;
TimeSpan utcOffset = new(hours * sign, minutes * sign, 0);
return s_epoch.AddMilliseconds(unixTime).ToOffset(utcOffset);
}
public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options)
{
long unixTime = Convert.ToInt64((value - s_epoch).TotalMilliseconds);
TimeSpan utcOffset = value.Offset;
string formatted = string.Create(CultureInfo.InvariantCulture, $"/Date({unixTime}{(utcOffset >= TimeSpan.Zero ? "+" : "-")}{utcOffset:hhmm})/");
writer.WriteStringValue(formatted);
}
}
sealed class UnixEpochDateTimeConverter : JsonConverter<DateTime>
{
static readonly DateTime s_epoch = new(1970, 1, 1, 0, 0, 0);
static readonly Regex s_regex = new("^/Date\\(([+-]*\\d+)\\)/$", RegexOptions.CultureInvariant);
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
string formatted = reader.GetString()!;
Match match = s_regex.Match(formatted);
if (
!match.Success
|| !long.TryParse(match.Groups[1].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out long unixTime))
{
throw new JsonException();
}
return s_epoch.AddMilliseconds(unixTime);
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
long unixTime = Convert.ToInt64((value - s_epoch).TotalMilliseconds);
string formatted = string.Create(CultureInfo.InvariantCulture, $"/Date({unixTime})/");
writer.WriteStringValue(formatted);
}
}
Para obter mais informações, consulte Suporte a DateTime e DateTimeOffset em System.Text.Json.
Chamadas de retorno
Newtonsoft.Json
Permite executar código personalizado em vários pontos do processo de serialização ou desserialização:
- OnDeserializing (ao começar a desserializar um objeto)
- OnDeserialized (quando termina de desserializar um objeto)
- OnSerializing (ao começar a serializar um objeto)
- OnSerialized (quando terminar de serializar um objeto)
System.Text.Json Expõe as mesmas notificações durante a serialização e desserialização. Para usá-los, implemente uma ou mais das seguintes interfaces do System.Text.Json.Serialization namespace:
Aqui está um exemplo que verifica uma propriedade nula e grava mensagens no início e no final da serialização e desserialização:
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Callbacks
{
public class WeatherForecast :
IJsonOnDeserializing, IJsonOnDeserialized,
IJsonOnSerializing, IJsonOnSerialized
{
public DateTime Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
void IJsonOnDeserializing.OnDeserializing() => Console.WriteLine("\nBegin deserializing");
void IJsonOnDeserialized.OnDeserialized()
{
Validate();
Console.WriteLine("Finished deserializing");
}
void IJsonOnSerializing.OnSerializing()
{
Console.WriteLine("Begin serializing");
Validate();
}
void IJsonOnSerialized.OnSerialized() => Console.WriteLine("Finished serializing");
private void Validate()
{
if (Summary is null)
{
Console.WriteLine("The 'Summary' property is 'null'.");
}
}
}
public class Program
{
public static void Main()
{
var weatherForecast = new WeatherForecast
{
Date = DateTime.Parse("2019-08-01"),
TemperatureCelsius = 25,
};
string jsonString = JsonSerializer.Serialize(weatherForecast);
Console.WriteLine(jsonString);
weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(jsonString);
Console.WriteLine($"Date={weatherForecast?.Date}");
Console.WriteLine($"TemperatureCelsius={weatherForecast?.TemperatureCelsius}");
Console.WriteLine($"Summary={weatherForecast?.Summary}");
}
}
}
// output:
//Begin serializing
//The 'Summary' property is 'null'.
//Finished serializing
//{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":null}
//Begin deserializing
//The 'Summary' property is 'null'.
//Finished deserializing
//Date=8/1/2019 12:00:00 AM
//TemperatureCelsius = 25
//Summary=
O OnDeserializing
código não tem acesso à nova instância POCO. Para manipular a nova instância POCO no início da desserialização, coloque esse código no construtor POCO.
Criadores e arrendatários de propriedades não públicas
Newtonsoft.Json
pode usar setters e getters de propriedades particulares e internas por meio do JsonProperty
atributo.
System.Text.Json suporta setters e getters de propriedades privadas e internas por meio do atributo [JsonInclude ]. Para obter um código de exemplo, consulte Acessadores de propriedade não pública.
Preencher objetos existentes
O JsonConvert.PopulateObject
método em Newtonsoft.Json
desserializa um documento JSON para uma instância existente de uma classe, em vez de criar uma nova instância.
System.Text.Json Sempre cria uma nova instância do tipo de destino usando o construtor Parameterless público padrão. Os conversores personalizados podem desserializar para uma instância existente.
Reutilizar em vez de substituir propriedades
A partir do .NET 8, System.Text.Json oferece suporte à reutilização de propriedades inicializadas em vez de substituí-las. Existem algumas diferenças de comportamento, sobre as quais você pode ler na proposta da API.
Para obter mais informações, consulte Preencher propriedades inicializadas.
Preencher propriedades sem setters
A partir do .NET 8, System.Text.Json oferece suporte ao preenchimento de propriedades, incluindo aquelas que não têm um setter. Para obter mais informações, consulte Preencher propriedades inicializadas.
Política de nomenclatura de casos de cobra
System.Text.Json Inclui uma política de nomenclatura interna para caso de cobra. No entanto, existem algumas diferenças de comportamento com Newtonsoft.Json
para algumas entradas. A tabela a seguir mostra algumas dessas diferenças ao converter entradas usando a JsonNamingPolicy.SnakeCaseLower política.
Entrada | Newtonsoft.Json Resultado | System.Text.Json Resultado |
---|---|---|
"AB1" | "a_b1" | "AB1" |
"SHA512Gerenciado" | "sh_a512_managed" | "sha512_managed" |
"abc123DEF456" | "abc123_de_f456" | "abc123_def456" |
"KEBAB-CASE" | "keba_b-_case" | "Caso Kebab" |
Atributos System.Runtime.Serialization
System.Runtime.Serializationatributos como DataContractAttribute, DataMemberAttributee IgnoreDataMemberAttribute permitem definir um contrato de dados. Um contrato de dados é um acordo formal entre um serviço e um cliente que descreve abstratamente os dados a serem trocados. O contrato de dados define com precisão quais propriedades são serializadas para troca.
System.Text.Json não tem suporte interno para esses atributos. No entanto, a partir do .NET 7, você pode usar um resolvedor de tipo personalizado para adicionar suporte. Para obter um exemplo, consulte ZCS. DataContractResolver.
Números octais
Newtonsoft.Json
trata números com um zero à esquerda como números octais.
System.Text.Json não permite zeros à esquerda porque a especificação RFC 8259 não os permite.
Lidar com membros ausentes
Se o JSON que está sendo desserializado incluir propriedades que estão faltando no tipo de destino, Newtonsoft.Json
pode ser configurado para lançar exceções. Por padrão, System.Text.Json ignora propriedades extras no JSON, exceto quando você usa o atributo [JsonExtensionData].
No .NET 8 e versões posteriores, você pode definir sua preferência para ignorar ou não permitir propriedades JSON não mapeadas usando um dos seguintes meios:
- Aplique o JsonUnmappedMemberHandlingAttribute atributo ao tipo para o qual você está desserializando.
- Para definir sua preferência globalmente, defina a JsonSerializerOptions.UnmappedMemberHandling propriedade. Ou, para geração de origem, defina a JsonSourceGenerationOptionsAttribute.UnmappedMemberHandling propriedade e aplique o atributo à sua JsonSerializerContext classe.
- Personalize a JsonTypeInfo.UnmappedMemberHandling propriedade.
JsonObjectAttribute
Newtonsoft.Json
tem um atributo, JsonObjectAttribute
, que pode ser aplicado no nível do tipo para controlar quais membros são serializados, como null
os valores são manipulados e se todos os membros são necessários.
System.Text.Json não tem nenhum atributo equivalente que possa ser aplicado em um tipo. Para alguns comportamentos, como null
manipulação de valor, você pode configurar o mesmo comportamento no global JsonSerializerOptions ou individualmente em cada propriedade.
Considere o exemplo a seguir que usa Newtonsoft.Json.JsonObjectAttribute
para especificar que todas as null
propriedades devem ser ignoradas:
[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)]
public class Person { ... }
No System.Text.Json, você pode definir o comportamento para todos os tipos e propriedades:
JsonSerializerOptions options = new()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
string json = JsonSerializer.Serialize<Person>(person, options);
Ou você pode definir o comportamento em cada propriedade separadamente:
public class Person
{
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Name { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public int? Age { get; set; }
}
Em seguida, considere o exemplo a seguir que usa Newtonsoft.Json.JsonObjectAttribute
para especificar que todas as propriedades de membro devem estar presentes no JSON:
[JsonObject(ItemRequired = Required.Always)]
public class Person { ... }
Você pode obter o mesmo comportamento adicionando System.Text.Json o modificador C# required
ou o JsonRequiredAttributea cada propriedade. Para obter mais informações, consulte Propriedades necessárias.
public class Person
{
[JsonRequired]
public string? Name { get; set; }
public required int? Age { get; set; }
}
TraceWriter
Newtonsoft.Json
Permite depurar usando um TraceWriter
para exibir logs gerados por serialização ou desserialização.
System.Text.Json não faz registro.
JsonDocument e JsonElement em comparação com JToken (como JObject, JArray)
System.Text.Json.JsonDocument fornece a capacidade de analisar e criar um DOM (Document Object Model) somente leitura a partir de cargas úteis JSON existentes. O DOM fornece acesso aleatório aos dados em uma carga JSON útil. Os elementos JSON que compõem a carga útil podem ser acessados através do JsonElement tipo. O JsonElement
tipo fornece APIs para converter texto JSON em tipos .NET comuns.
JsonDocument
expõe uma RootElement propriedade.
A partir do .NET 6, você pode analisar e criar um DOM mutável a partir de cargas JSON existentes usando o JsonNode tipo e outros tipos no System.Text.Json.Nodes namespace. Para obter mais informações, consulte Usar JsonNode
.
JsonDocument é IDisposable
JsonDocument
Cria uma exibição na memória dos dados em um buffer em pool. Portanto, ao contrário JObject
ou JArray
de , o tipo implementa Newtonsoft.Json
JsonDocument
e precisa ser usado dentro de um bloco de IDisposable
uso. Para obter mais informações, consulte JsonDocument is IDisposable.
JsonDocument é somente leitura
O System.Text.Json DOM não pode adicionar, remover ou modificar elementos JSON. Ele foi projetado dessa forma para desempenho e para reduzir alocações para analisar tamanhos de carga JSON comuns (ou seja, < 1 MB).
JsonElement é uma estrutura de união
JsonDocument
expõe a RootElement
propriedade as a do tipo JsonElement, que é um tipo struct de união que engloba qualquer elemento JSON.
Newtonsoft.Json
usa tipos hierárquicos dedicados como JObject
, JArray
, JToken
, e assim por diante.
JsonElement
é o que você pode pesquisar e enumerar, e você pode usar JsonElement
para materializar elementos JSON em tipos .NET.
A partir do .NET 6, você pode usar JsonNode tipos System.Text.Json.Nodes e tipos no namespace que correspondem a JObject
, JArray
e JToken
. Para obter mais informações, consulte Usar JsonNode
.
Como pesquisar subelementos JsonDocument e JsonElement
As pesquisas por tokens JSON usando JObject
ou JArray
de Newtonsoft.Json
tendem a ser relativamente rápidas porque são pesquisas em algum dicionário. Em comparação, as pesquisas exigem JsonElement
uma pesquisa sequencial das propriedades e, portanto, são relativamente lentas (por exemplo, ao usar TryGetProperty
).
System.Text.Json foi projetado para minimizar o tempo de análise inicial em vez do tempo de pesquisa. Para obter mais informações, consulte Como pesquisar subelementos JsonDocument e JsonElement.
Utf8JsonReader vs. JsonTextReader
System.Text.Json.Utf8JsonReaderé um leitor de alto desempenho, baixa alocação, somente encaminhamento para texto JSON codificado UTF-8, lido a partir de um <> ReadOnlySpanou < ReadOnlySequence>. O Utf8JsonReader
é um tipo de baixo nível que pode ser usado para criar analisadores e desserializadores personalizados.
Utf8JsonReader é uma ref struct
O JsonTextReader
in Newtonsoft.Json
é uma classe. O Utf8JsonReader
tipo difere na medida em que é um ref struct. Para obter mais informações, consulte ref struct limitations for Utf8JsonReader.
Ler valores nulos em tipos de valor anuláveis
Newtonsoft.Json
fornece APIs que retornam Nullable<T>, como ReadAsBoolean
, que lida com um Null
TokenType
para você retornando um bool?
arquivo . As APIs internas System.Text.Json
retornam apenas tipos de valor não anuláveis. Para obter mais informações, consulte Ler valores nulos em tipos de valor anuláveis.
Multi-target para leitura JSON
Se você precisar continuar a usar Newtonsoft.Json
para determinadas estruturas de destino, poderá ter vários destinos e duas implementações. No entanto, isso não é trivial e exigiria alguma #ifdefs
duplicação de fontes. Uma maneira de compartilhar o máximo de código possível é criar um ref struct
wrapper em torno Utf8JsonReader e Newtonsoft.Json.JsonTextReader
. Este invólucro unificaria a área de superfície pública, isolando as diferenças comportamentais. Isso permite isolar as alterações principalmente na construção do tipo, além de passar o novo tipo por referência. Este é o padrão que a biblioteca Microsoft.Extensions.DependencyModel segue:
Utf8JsonWriter vs. JsonTextWriter
System.Text.Json.Utf8JsonWriter é uma maneira de alto desempenho para escrever texto JSON codificado em UTF-8 a partir de tipos .NET comuns como String
, Int32
e DateTime
. O gravador é um tipo de baixo nível que pode ser usado para criar serializadores personalizados.
Escrever valores brutos
Newtonsoft.Json
tem um WriteRawValue
método que grava JSON bruto onde um valor é esperado.
System.Text.Json tem um equivalente direto: Utf8JsonWriter.WriteRawValue. Para obter mais informações, consulte Escrever JSON bruto.
Personalizar o formato JSON
JsonTextWriter
inclui as seguintes configurações, para as quais Utf8JsonWriter não tem equivalente:
-
QuoteChar - Especifica o caractere a ser usado para cercar valores de cadeia de caracteres.
Utf8JsonWriter
usa sempre aspas duplas. -
QuoteName - Especifica se os nomes de propriedade devem ou não ser cercados por aspas.
Utf8JsonWriter
rodeia-os sempre de citações.
A partir do .NET 9, você pode personalizar o caractere de recuo e o tamanho para Utf8JsonWriter usar as JsonWriterOptions opções expostas pelo struct:
JsonTextWriter
inclui as seguintes configurações, para as quais Utf8JsonWriter
não tem equivalente:
-
Recuo - Especifica quantos caracteres recuar.
Utf8JsonWriter
sempre recua por 2 caracteres. -
IndentChar - Especifica o caractere a ser usado para recuo.
Utf8JsonWriter
sempre usa espaço em branco. -
QuoteChar - Especifica o caractere a ser usado para cercar valores de cadeia de caracteres.
Utf8JsonWriter
usa sempre aspas duplas. -
QuoteName - Especifica se os nomes de propriedade devem ou não ser cercados por aspas.
Utf8JsonWriter
rodeia-os sempre de citações.
Não há soluções alternativas que permitam personalizar o JSON produzido por Utf8JsonWriter
dessas maneiras.
Escrever valores de Timepan, Uri ou char
JsonTextWriter
fornece WriteValue
métodos para valores TimeSpan, Uri e char .
Utf8JsonWriter
não tem métodos equivalentes. Em vez disso, formate esses valores como cadeias de caracteres (chamando ToString()
, por exemplo) e chame WriteStringValue.
Multi-target para escrever JSON
Se você precisar continuar a usar Newtonsoft.Json
para determinadas estruturas de destino, poderá ter vários destinos e duas implementações. No entanto, isso não é trivial e exigiria alguma #ifdefs
duplicação de fontes. Uma maneira de compartilhar o máximo de código possível é criar um wrapper em torno Utf8JsonWriter e Newtonsoft.Json.JsonTextWriter
. Este invólucro unificaria a área de superfície pública, isolando as diferenças comportamentais. Isso permite isolar as alterações principalmente na construção do tipo.
A biblioteca Microsoft.Extensions.DependencyModel segue:
TypeNameHandling.All não suportado
A decisão de TypeNameHandling.All
excluir a funcionalidade equivalente foi intencional System.Text.Json
. Permitir que uma carga JSON especifique suas próprias informações de tipo é uma fonte comum de vulnerabilidades em aplicativos Web. Em particular, a configuração Newtonsoft.Json
com TypeNameHandling.All
permite que o cliente remoto incorpore um aplicativo executável inteiro dentro da própria carga JSON para que, durante a desserialização, o aplicativo Web extraia e execute o código incorporado. Para obter mais informações, consulte Friday the 13th JSON attacks PowerPoint e Friday the 13th JSON attacks details.
Consultas de caminho JSON não suportadas
O JsonDocument
DOM não oferece suporte à consulta usando o caminho JSON.
Em um JsonNode DOM, cada JsonNode
instância tem um GetPath
método que retorna um caminho para esse nó. Mas não há nenhuma API interna para lidar com consultas baseadas em cadeias de caracteres de consulta de caminho JSON.
Para obter mais informações, consulte o problema dotnet/runtime #31068 do GitHub.
Alguns limites não configuráveis
System.Text.Json define limites que não podem ser alterados para alguns valores, como o tamanho máximo do token em caracteres (166 MB) e na base 64 (125 MB). Para obter mais informações, consulte JsonConstants
o código-fonte e a questão do GitHub dotnet/runtime #39953.
NaN, Infinito, -Infinito
Newtonsoft analisa NaN
, Infinity
e -Infinity
JSON string tokens. Com System.Text.Json, use JsonNumberHandling.AllowNamedFloatingPointLiterals. Para obter informações sobre como usar essa configuração, consulte Permitir ou gravar números entre aspas.
Use o Copilot do GitHub para migrar
Você pode obter ajuda de codificação do GitHub Copilot para migrar seu código do Newtonsoft.Json
para System.Text.Json
dentro do seu IDE. Você pode personalizar o prompt de acordo com suas necessidades.
Exemplo de prompt para o Copilot Chat
convert the following code to use System.Text.Json
Product product = new Product();
product.Name = "Apple";
product.ExpiryDate = new DateTime(2024, 08, 08);
product.Price = 3.99M;
product.Sizes = new string[] { "Small", "Medium", "Large" };
string output = JsonConvert.SerializeObject(product);
Console.WriteLine(output);
O GitHub Copilot é alimentado por IA, então surpresas e erros são possíveis. Para obter mais informações, consulte Copilot FAQs.
Saiba mais sobre Copiloto GitHub no Visual Studio e Copiloto GitHub no VS Code.