System.Text.Json으로 속성 이름 및 값을 사용자 지정하는 방법

기본적으로 대/소문자를 비롯한 속성 이름 및 사전 키는 JSON 출력에서 변경되지 않습니다. 열거형 값은 숫자로 표시됩니다. 그리고 속성은 정의된 순서대로 직렬화됩니다. 그러나 다음을 통해 이러한 동작을 사용자 지정할 수 있습니다.

  • 직렬화된 특정 속성 이름을 지정합니다.
  • 속성 이름 및 사전 키에 대한 기본 제공 명명 정책(예: camelCase, snake_case 또는 kebab-case)를 사용합니다.
  • 속성 이름 및 사전 키에 대한 사용자 지정 명명 정책을 사용합니다.
  • 명명 정책을 사용하거나 사용하지 않고 열거형 값을 문자열로 직렬화합니다.
  • 직렬화된 속성의 순서를 구성합니다.

참고 항목

웹 기본 명명 정책은 카멜 대/소문자입니다.

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
}

이 특성을 통해 설정된 속성 이름은 다음과 같은 특징이 있습니다.

기본 제공 명명 정책 사용

다음 표에서는 기본 제공 명명 정책과 속성 이름에 미치는 영향을 보여줍니다.

명명 정책 설명 원래 속성 이름 변환된 속성 이름
CamelCase 첫 번째 단어는 소문자로 시작합니다.
연속 단어는 대문자로 시작합니다.
TempCelsius tempCelsius
KebabCaseLower* 단어는 하이픈으로 구분됩니다.
모든 문자는 소문자입니다.
TempCelsius temp-celsius
KebabCaseUpper* 단어는 하이픈으로 구분됩니다.
모든 문자는 대문자입니다.
TempCelsius TEMP-CELSIUS
SnakeCaseLower* 단어는 밑줄로 구분됩니다.
모든 문자는 소문자입니다.
TempCelsius temp_celsius
SnakeCaseUpper* 단어는 밑줄로 구분됩니다.
모든 문자는 대문자입니다.
TempCelsius TEMP_CELSIUS

* .NET 8 이상 버전에서 사용할 수 있습니다.

다음 예제에서는 JsonSerializerOptions.PropertyNamingPolicy을(를) JsonNamingPolicy.CamelCase(으)로 설정하여 모든 JSON 속성 이름에 카멜 대/소문자를 사용하는 방법을 보여줍니다.

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
}

명명 정책:

  • 직렬화 및 역직렬화에 적용됩니다.
  • [JsonPropertyName] 특성에 의해 재정의됩니다. 이러한 이유로 이 예제의 JSON 속성 이름 Wind는 카멜식 대/소문자가 아닙니다.

참고 항목

기본 제공 명명 정책은 서로게이트 쌍인 문자를 지원하지 않습니다. 자세한 내용은 dotnet/런타임 이슈 90352를 참조하세요.

사용자 지정 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는 대문자가 아닙니다.

사전 키에 명명 정책 사용

직렬화할 개체의 속성이 Dictionary<string,TValue> 형식인 경우 카멜 대/소문자 등의 명명 정책을 사용하여 string 키를 변환할 수 있습니다. 이렇게 하려면 JsonSerializerOptions.DictionaryKeyPolicy을(를) 원하는 명명 정책으로 설정합니다. 다음 예제에서는 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)

키-값 쌍 "ColdMinTemp", 20"HotMinTemp", 40가 있는 TemperatureRanges라는 사전이 포함된 개체를 직렬화하면 다음 예제와 같은 JSON 출력이 생성됩니다.

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

사전 키에 대한 명명 정책은 serialization에만 적용됩니다. 사전을 역직렬화하는 경우 기본이 아닌 명명 정책으로 JsonSerializerOptions.DictionaryKeyPolicy을(를) 설정하더라도 키가 JSON 파일과 일치합니다.

문자열인 열거형

기본적으로 열거형은 숫자로 직렬화됩니다. 열거형 이름을 문자열로 직렬화하려면 JsonStringEnumConverter 또는 JsonStringEnumConverter<TEnum> 변환기를 사용합니다. JsonStringEnumConverter<TEnum>만 네이티브 AOT 런타임에서 지원됩니다.

기본적으로 열거형은 숫자로 직렬화됩니다. 열거형 이름을 문자열로 직렬화하려면 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
}

다음 샘플 코드는 숫자 값 대신 열거형 이름을 직렬화하고, 이름을 카멜식 대/소문자로 변환합니다.

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를 사용한 역직렬화를 보여줍니다.

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)

열거형에 JsonConverterAttribute 주석을 추가하여 사용할 변환기를 지정할 수도 있습니다. 다음 예제에서는 JsonConverterAttribute 특성을 사용하여 JsonStringEnumConverter<TEnum>(.NET 8 이상 버전에서 사용 가능)를 지정하는 방법을 보여줍니다. 예를 들어 열거형을 포함하는 다음 클래스를 직렬화해야 한다고 가정해 봅시다.

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
}

다음 샘플 코드는 숫자 값 대신 열거형 이름을 직렬화합니다.

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

그 결과로 얻는 JSON은 다음 예제와 유사합니다.

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

원본 생성과 함께 변환기를 사용하려면 열거형 필드를 문자열로 직렬화를 참조하세요.

직렬화된 속성의 순서 구성

기본적으로 속성은 클래스에서 정의된 순서대로 직렬화됩니다. [JsonPropertyOrder] 특성을 사용하면 직렬화에서 JSON 출력의 속성 순서를 지정할 수 있습니다. Order 속성의 기본값은 0입니다. 속성을 기본값이 설정된 속성 뒤에 배치하려면 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"
//}

참고 항목