如何使用 System.Text.Json 自定义属性名称和值

默认情况下,属性名称和字典键在 JSON 输出中保持不变,包括大小写。 枚举值表示为数字。 本文将指导如何进行以下操作:

注意

Web 默认值为 camel 形式大小写。

对于需要对 JSON 属性名称和值进行特殊处理的其他方案,可以实现自定义转换器

自定义单个属性名称

若要设置单个属性的名称,请使用 [JsonPropertyName] 特性。

下面是要进行序列化的示例类型和生成的 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
}

此特性设置的属性名称:

对所有 JSON 属性名称使用 camel 大小写

若要对所有 JSON 属性名称使用 camel 大小写,请将 JsonSerializerOptions.PropertyNamingPolicy 设置为 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)

下面是要进行序列化的示例类和 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
}

camel 大小写属性命名策略:

  • 适用于序列化和反序列化。
  • [JsonPropertyName] 特性替代。 这便是示例中的 JSON 属性名称 Wind 不是 camel 大小写的原因。

使用自定义 JSON 属性命名策略

若要使用自定义 JSON 属性命名策略,请创建派生自 JsonNamingPolicy 的类,并替代 ConvertName 方法,如下面的示例中所示:

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

然后,将 JsonSerializerOptions.PropertyNamingPolicy 属性设置为命名策略类的实例:

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)

下面是要进行序列化的示例类和 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
}

JSON 属性命名策略:

  • 适用于序列化和反序列化。
  • [JsonPropertyName] 特性替代。 这便是示例中的 JSON 属性名称 Wind 不是大写的原因。

Camel 大小写字典键

如果要序列化的对象的属性为 Dictionary<string,TValue> 类型,则 string 键可转换为 camel 大小写。 为此,请将 DictionaryKeyPolicy 设置为 JsonNamingPolicy.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)

使用名为 TemperatureRanges 且具有键值对 "ColdMinTemp", 20"HotMinTemp", 40 的字典序列化对象会产生类似于以下示例的 JSON 输出:

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

字典键的 camel 大小写命名策略仅适用于序列化。 如果对字典进行反序列化,即使为 DictionaryKeyPolicy指定 JsonNamingPolicy.CamelCase,键也会与 JSON 文件匹配。

作为字符串的枚举

默认情况下,枚举会序列化为数字。 若要将枚举名称序列化为字符串,请使用 JsonStringEnumConverter

例如,假设需要序列化以下具有枚举的类:

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

如果 Summary 为 Hot,则默认情况下序列化的 JSON 具有数值 3:

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

下面的示例代码序列化枚举名称(而不是数值),并将名称转换为 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)

生成的 JSON 类似于以下示例:

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

内置 JsonStringEnumConverter 还可以反序列化字符串值。 在没有指定的命名策略,或者具有 CamelCase 命名策略的情况下,可使用它。 它不支持其他命名策略,例如蛇形命名法。 下面的示例演示如何使用 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)

若要了解在使用蛇形命名法命名策略时支持反序列化的自定义转换器代码,请参阅支持枚举字符串值反序列化

配置序列化属性的顺序

通过 [JsonPropertyOrder] 特性,可指定序列化的 JSON 输出中的属性顺序。 Order 属性的默认值是零。 如果将 Order 设置为正数,则会将属性放置在具有默认值的属性后面。 如果 Order 是负数,则会将属性放置在具有默认值的属性前面。 属性按 Order 值从小到大的顺序编写的。 下面是一个示例:

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"
//}

请参阅