Personalización de los nombres y valores de propiedades con System.Text.Json

De forma predeterminada, los nombres de propiedad y las claves de diccionario no se modifican en la salida JSON, ni siquiera el uso de mayúsculas y minúsculas. Los valores de enumeración se representan como números. Y las propiedades se serializan en el orden en que se definen. Sin embargo, puede personalizar estos comportamientos mediante:

  • Especificar nombres de propiedad serializados específicos.
  • Con una directiva de nomenclatura integrada, como camelCase, snake_case o kebab-case, para nombres de propiedad y claves de diccionario.
  • Usar una directiva de nomenclatura personalizada para los nombres de las propiedades y las claves del diccionario.
  • Serializar valores de enumeración como cadenas, con o sin una directiva de nomenclatura.
  • Configuración del orden de las propiedades serializadas.

Nota:

La directiva de nomenclatura web predeterminada es el caso camel.

En el caso de otros escenarios que requieran un tratamiento especial de los nombres y valores de propiedades JSON, puede implementar convertidores personalizados.

Personalizar nombres de propiedades individuales

Para establecer el nombre de propiedades individuales, use el atributo [JsonPropertyName].

Aquí se muestra un tipo de ejemplo que se serializa y el JSON resultante:

public class WeatherForecastWithPropertyNameAttribute
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
    [JsonPropertyName("Wind")]
    public int WindSpeed { get; set; }
}
Public Class WeatherForecastWithPropertyNameAttribute
    Public Property [Date] As DateTimeOffset
    Public Property TemperatureCelsius As Integer
    Public Property Summary As String

    <JsonPropertyName("Wind")>
    Public Property WindSpeed As Integer

End Class
{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "Hot",
  "Wind": 35
}

Nombre de propiedad establecido por este atributo:

Uso de una directiva de nomenclatura integrada

En la tabla siguiente se muestran las directivas de nomenclatura integradas y cómo afectan a los nombres de propiedad.

Directiva de nomenclatura Descripción Nombre de propiedad original Nombre de propiedad convertido
CamelCase La primera palabra comienza con un carácter en minúsculas.
Las palabras sucesivas comienzan con un carácter en mayúsculas.
TempCelsius tempCelsius
KebabCaseLower* Las palabras están separadas por guiones.
Todos los caracteres están en minúsculas.
TempCelsius temp-celsius
KebabCaseUpper* Las palabras están separadas por guiones.
Todos los caracteres están en mayúsculas.
TempCelsius TEMP-CELSIUS
SnakeCaseLower* Las palabras están separadas por caracteres de subrayado.
Todos los caracteres están en minúsculas.
TempCelsius temp_celsius
SnakeCaseUpper* Las palabras están separadas por caracteres de subrayado.
Todos los caracteres están en mayúsculas.
TempCelsius TEMP_CELSIUS

* Disponible en .NET 8 y versiones posteriores.

El ejemplo siguiente se muestra cómo utilizar el caso camel para todos los nombres de propiedad JSON mediante el establecimiento de JsonSerializerOptions.PropertyNamingPolicy a JsonNamingPolicy.CamelCase :

var serializeOptions = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecast, serializeOptions);
Dim serializeOptions As JsonSerializerOptions = New JsonSerializerOptions With {
    .PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    .WriteIndented = True
}
jsonString = JsonSerializer.Serialize(weatherForecast, serializeOptions)

Aquí se muestra una clase de ejemplo que se serializa y la salida JSON:

public class WeatherForecastWithPropertyNameAttribute
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
    [JsonPropertyName("Wind")]
    public int WindSpeed { get; set; }
}
Public Class WeatherForecastWithPropertyNameAttribute
    Public Property [Date] As DateTimeOffset
    Public Property TemperatureCelsius As Integer
    Public Property Summary As String

    <JsonPropertyName("Wind")>
    Public Property WindSpeed As Integer

End Class
{
  "date": "2019-08-01T00:00:00-07:00",
  "temperatureCelsius": 25,
  "summary": "Hot",
  "Wind": 35
}

La directiva de nomenclatura:

  • Se aplica a la serialización y la deserialización.
  • Se invalida con atributos [JsonPropertyName]. Este es el motivo por el que el nombre de la propiedad JSON Wind del ejemplo no usa mayúsculas y minúsculas combinadas Camel.

Nota:

Ninguna de las directivas de nomenclatura integradas admite letras que son pares suplentes. Para obtener más información, consulte problema dotnet/runtime 90352.

Uso de una directiva de nomenclatura de propiedades JSON personalizada

Para usar una directiva de nomenclatura de propiedades JSON personalizada, cree una clase que derive de JsonNamingPolicy e invalide el método ConvertName, tal y como se muestra en el ejemplo siguiente:

using System.Text.Json;

namespace SystemTextJsonSamples
{
    public class UpperCaseNamingPolicy : JsonNamingPolicy
    {
        public override string ConvertName(string name) =>
            name.ToUpper();
    }
}
Imports System.Text.Json

Namespace SystemTextJsonSamples

    Public Class UpperCaseNamingPolicy
        Inherits JsonNamingPolicy

        Public Overrides Function ConvertName(name As String) As String
            Return name.ToUpper()
        End Function

    End Class

End Namespace

Establezca luego la propiedad JsonSerializerOptions.PropertyNamingPolicy en una instancia de la clase de directiva de nomenclatura:

var options = new JsonSerializerOptions
{
    PropertyNamingPolicy = new UpperCaseNamingPolicy(),
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecast, options);
Dim options As JsonSerializerOptions = New JsonSerializerOptions With {
    .PropertyNamingPolicy = New UpperCaseNamingPolicy,
    .WriteIndented = True
}
jsonString = JsonSerializer.Serialize(weatherForecast1, options)

Aquí se muestra una clase de ejemplo que se serializa y la salida JSON:

public class WeatherForecastWithPropertyNameAttribute
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
    [JsonPropertyName("Wind")]
    public int WindSpeed { get; set; }
}
Public Class WeatherForecastWithPropertyNameAttribute
    Public Property [Date] As DateTimeOffset
    Public Property TemperatureCelsius As Integer
    Public Property Summary As String

    <JsonPropertyName("Wind")>
    Public Property WindSpeed As Integer

End Class
{
  "DATE": "2019-08-01T00:00:00-07:00",
  "TEMPERATURECELSIUS": 25,
  "SUMMARY": "Hot",
  "Wind": 35
}

La directiva de nomenclatura de propiedades JSON personalizada:

  • Se aplica a la serialización y la deserialización.
  • Se invalida con atributos [JsonPropertyName]. Este es el motivo por el que el nombre de la propiedad JSON Wind del ejemplo no usa mayúsculas.

Usar una directiva de nomenclatura para las claves de diccionario

Si una propiedad de un objeto a serializar es de tipo Dictionary<string,TValue>, las claves string se pueden convertir usando una directiva de nomenclatura, como el caso camel. Para ello, establezca en JsonSerializerOptions.DictionaryKeyPolicy la directiva de nomenclatura deseada. En el ejemplo siguiente se usa la directiva de nomenclatura CamelCase :

var options = new JsonSerializerOptions
{
    DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecast, options);
Dim options As JsonSerializerOptions = New JsonSerializerOptions With {
    .DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
    .WriteIndented = True
}
jsonString = JsonSerializer.Serialize(weatherForecast, options)

La serialización de un objeto con un diccionario denominado TemperatureRanges que tenga pares clave-valor "ColdMinTemp", 20 y "HotMinTemp", 40 se traduciría en una salida JSON similar a la del ejemplo siguiente:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "Hot",
  "TemperatureRanges": {
    "coldMinTemp": 20,
    "hotMinTemp": 40
  }
}

Las directivas de nomenclatura de las claves de diccionario solo se aplican a la serialización. Si deserializa un diccionario, las claves coincidirán con el archivo JSON aunque se establezca JsonSerializerOptions.DictionaryKeyPolicy en una directiva de nomenclatura no predeterminada.

Enumeraciones como cadenas

De forma predeterminada, las enumeraciones se serializan como números. Para serializar nombres de enumeración como cadenas, use el convertidor de JsonStringEnumConverter o JsonStringEnumConverter<TEnum>. Solo JsonStringEnumConverter<TEnum> es compatible con el entorno runtime de AOT nativo.

De forma predeterminada, las enumeraciones se serializan como números. Para serializar nombres de enumeración como cadenas, use el convertidor de JsonStringEnumConverter.

Por ejemplo, supongamos que hay que serializar la siguiente clase que tiene una enumeración:

public class WeatherForecastWithEnum
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public Summary? Summary { get; set; }
}

public enum Summary
{
    Cold, Cool, Warm, Hot
}
Public Class WeatherForecastWithEnum
    Public Property [Date] As DateTimeOffset
    Public Property TemperatureCelsius As Integer
    Public Property Summary As Summary
End Class

Public Enum Summary
    Cold
    Cool
    Warm
    Hot
End Enum

Si el resumen es Hot, el JSON serializado tiene el valor numérico 3 de forma predeterminada:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": 3
}

En el código de ejemplo siguiente se serializan los nombres de enumeración en lugar de los valores numéricos y los nombres se convierten en mayúsculas y minúsculas combinadas Camel:

options = new JsonSerializerOptions
{
    WriteIndented = true,
    Converters =
    {
        new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
    }
};
jsonString = JsonSerializer.Serialize(weatherForecast, options);
options = New JsonSerializerOptions With {
    .WriteIndented = True
}
options.Converters.Add(New JsonStringEnumConverter(JsonNamingPolicy.CamelCase))
jsonString = JsonSerializer.Serialize(weatherForecast, options)

El JSON resultante tendrá un aspecto similar al siguiente:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "hot"
}

El elemento integrado JsonStringEnumConverter también puede deserializar los valores de cadena. Funciona con o sin una directiva de nomenclatura especificada. En el ejemplo siguiente se muestra la deserialización mediante CamelCase:

options = new JsonSerializerOptions
{
    Converters =
    {
        new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
    }
};
weatherForecast = JsonSerializer.Deserialize<WeatherForecastWithEnum>(jsonString, options)!;
options = New JsonSerializerOptions
options.Converters.Add(New JsonStringEnumConverter(JsonNamingPolicy.CamelCase))
weatherForecast = JsonSerializer.Deserialize(Of WeatherForecastWithEnum)(jsonString, options)

También puede especificar el convertidor que se va a usar anotando la enumeración con JsonConverterAttribute. En el ejemplo siguiente se muestra cómo especificar JsonStringEnumConverter<TEnum>(disponible en .NET 8 y versiones posteriores) mediante el atributoJsonConverterAttribute. Por ejemplo, supongamos que hay que serializar la siguiente clase que tiene una enumeración:

public class WeatherForecastWithPrecipEnum
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public Precipitation? Precipitation { get; set; }
}

[JsonConverter(typeof(JsonStringEnumConverter<Precipitation>))]
public enum Precipitation
{
    Drizzle, Rain, Sleet, Hail, Snow
}

El código de ejemplo siguiente serializa los nombres de enumeración en lugar de los valores numéricos:

var options = new JsonSerializerOptions
{
    WriteIndented = true,
};
jsonString = JsonSerializer.Serialize(weatherForecast, options);

El JSON resultante tendrá un aspecto similar al siguiente:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Precipitation": "Sleet"
}

Para usar el convertidor con generación de origen, consulte Serializar campos de enumeración como cadenas.

Configurar el orden de las propiedades serializadas

De forma predeterminada, las propiedades se serializan en el orden en que se definen en su clase. El atributo [JsonPropertyOrder] permite especificar el orden de las propiedades en la salida JSON de la serialización. El valor predeterminado de la propiedad Order es cero. Se establece Order en un número positivo para colocar una propiedad detrás de las que tienen el valor predeterminado. Un valor negativo Order coloca una propiedad delante de las que tienen el valor predeterminado. Las propiedades se escriben por orden, del valor Order más bajo al más alto. Este es un ejemplo:

using System.Text.Json;
using System.Text.Json.Serialization;

namespace PropertyOrder
{
    public class WeatherForecast
    {
        [JsonPropertyOrder(-5)]
        public DateTime Date { get; set; }
        public int TemperatureC { get; set; }
        [JsonPropertyOrder(-2)]
        public int TemperatureF { get; set; }
        [JsonPropertyOrder(5)]
        public string? Summary { get; set; }
        [JsonPropertyOrder(2)]
        public int WindSpeed { get; set; }
    }

    public class Program
    {
        public static void Main()
        {
            var weatherForecast = new WeatherForecast
            {
                Date = DateTime.Parse("2019-08-01"),
                TemperatureC = 25,
                TemperatureF = 25,
                Summary = "Hot",
                WindSpeed = 10
            };

            var options = new JsonSerializerOptions { WriteIndented = true };
            string jsonString = JsonSerializer.Serialize(weatherForecast, options);
            Console.WriteLine(jsonString);
        }
    }
}
// output:
//{
//  "Date": "2019-08-01T00:00:00",
//  "TemperatureF": 25,
//  "TemperatureC": 25,
//  "WindSpeed": 10,
//  "Summary": "Hot"
//}

Vea también