System.Text.Json에서 원본 생성을 사용하는 방법

System.Text.Json의 원본 생성은 .NET 6 이상 버전에서 사용할 수 있습니다. 앱에서 사용하는 경우 앱의 언어 버전은 C# 9.0 이상이어야 합니다. 이 문서에서는 앱에서 원본 생성 지원 Serialization을 사용하는 방법을 보여 줍니다.

다양한 원본 생성 모드에 대한 자세한 내용은 원본 생성 모드를 참조하세요.

원본 생성 기본값 사용

모든 기본값(두 가지 모드, 기본 옵션)에서 원본 생성을 사용하려면 다음을 수행합니다.

  1. JsonSerializerContext에서 파생되는 partial 클래스를 만듭니다.

  2. 컨텍스트 클래스에 JsonSerializableAttribute를 적용하여 직렬화하거나 역직렬화할 형식을 지정합니다.

  3. 다음 중 하나를 수행하는 JsonSerializer 메서드를 호출합니다.

기본적으로 원본 생성 모드를 지정하지 않으면 두 원본 생성 모드가 모두 사용됩니다. 사용할 모드를 지정하는 방법에 대한 자세한 내용은 이 문서의 뒷부분에 있는 원본 생성 모드 지정을 참조하세요.

다음 예제에서 사용되는 형식은 다음과 같습니다.

public class WeatherForecast
{
    public DateTime Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
}

다음은 이전 WeatherForecast 클래스에 대한 원본 생성을 수행하도록 구성된 컨텍스트 클래스입니다.

[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(WeatherForecast))]
internal partial class SourceGenerationContext : JsonSerializerContext
{
}

WeatherForecast 멤버의 형식은 [JsonSerializable] 특성으로 명시적으로 지정할 필요가 없습니다. object으로 선언된 멤버는 이 규칙의 예외입니다. object로 선언된 멤버의 런타임 형식을 지정해야 합니다. 예를 들어 다음과 같은 코드가 있다고 가정하겠습니다.

public class WeatherForecast
{
    public object? Data { get; set; }
    public List<object>? DataList { get; set; }
}

또한 런타임에 booleanint 개체가 있다는 것을 알고 있습니다.

WeatherForecast wf = new() { Data = true, DataList = new List<object> { true, 1 } };

그러면 booleanint[JsonSerializable]로 선언해야 합니다.

[JsonSerializable(typeof(WeatherForecast))]
[JsonSerializable(typeof(bool))]
[JsonSerializable(typeof(int))]
public partial class WeatherForecastContext : JsonSerializerContext
{
}

컬렉션의 원본 생성을 지정하려면 컬렉션 형식과 함께 [JsonSerializable]을 사용합니다. 예: [JsonSerializable(typeof(List<WeatherForecast>))]

원본 생성을 사용하는 JsonSerializer 메서드

다음 예제에서 컨텍스트 형식의 static Default 속성은 기본 옵션을 사용하여 컨텍스트 형식의 인스턴스를 제공합니다. 컨텍스트 인스턴스는 JsonTypeInfo<WeatherForecast> 인스턴스를 반환하는 WeatherForecast 속성을 제공합니다. [JsonSerializable] 특성의 TypeInfoPropertyName 속성을 사용하여 이 속성에 대해 다른 이름을 지정할 수 있습니다.

Serialization 예제

JsonTypeInfo<T>사용:

jsonString = JsonSerializer.Serialize(
    weatherForecast!, SourceGenerationContext.Default.WeatherForecast);

JsonSerializerContext사용:

jsonString = JsonSerializer.Serialize(
    weatherForecast, typeof(WeatherForecast), SourceGenerationContext.Default);

JsonSerializerOptions사용:

sourceGenOptions = new JsonSerializerOptions
{
    TypeInfoResolver = SourceGenerationContext.Default
};

jsonString = JsonSerializer.Serialize(
    weatherForecast, typeof(WeatherForecast), sourceGenOptions);

Deserialization 예제

JsonTypeInfo<T>사용:

weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(
    jsonString, SourceGenerationContext.Default.WeatherForecast);

JsonSerializerContext사용:

weatherForecast = JsonSerializer.Deserialize(
    jsonString, typeof(WeatherForecast), SourceGenerationContext.Default)
    as WeatherForecast;

JsonSerializerOptions사용:

var sourceGenOptions = new JsonSerializerOptions
{
    TypeInfoResolver = SourceGenerationContext.Default
};
weatherForecast = JsonSerializer.Deserialize(
    jsonString, typeof(WeatherForecast), sourceGenOptions)
    as WeatherForecast;

전체 프로그램 예제

다음은 전체 프로그램에서 앞에 나온 예제입니다.

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

namespace BothModesNoOptions
{
    public class WeatherForecast
    {
        public DateTime Date { get; set; }
        public int TemperatureCelsius { get; set; }
        public string? Summary { get; set; }
    }

    [JsonSourceGenerationOptions(WriteIndented = true)]
    [JsonSerializable(typeof(WeatherForecast))]
    internal partial class SourceGenerationContext : JsonSerializerContext
    {
    }

    public class Program
    {
        public static void Main()
        {
            string jsonString = """
                {
                    "Date": "2019-08-01T00:00:00",
                    "TemperatureCelsius": 25,
                    "Summary": "Hot"
                }
                """;
            WeatherForecast? weatherForecast;

            weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(
                jsonString, SourceGenerationContext.Default.WeatherForecast);
            Console.WriteLine($"Date={weatherForecast?.Date}");
            // output:
            //Date=8/1/2019 12:00:00 AM

            weatherForecast = JsonSerializer.Deserialize(
                jsonString, typeof(WeatherForecast), SourceGenerationContext.Default)
                as WeatherForecast;
            Console.WriteLine($"Date={weatherForecast?.Date}");
            // output:
            //Date=8/1/2019 12:00:00 AM

            var sourceGenOptions = new JsonSerializerOptions
            {
                TypeInfoResolver = SourceGenerationContext.Default
            };
            weatherForecast = JsonSerializer.Deserialize(
                jsonString, typeof(WeatherForecast), sourceGenOptions)
                as WeatherForecast;
            Console.WriteLine($"Date={weatherForecast?.Date}");
            // output:
            //Date=8/1/2019 12:00:00 AM

            jsonString = JsonSerializer.Serialize(
                weatherForecast!, SourceGenerationContext.Default.WeatherForecast);
            Console.WriteLine(jsonString);
            // output:
            //{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":"Hot"}

            jsonString = JsonSerializer.Serialize(
                weatherForecast, typeof(WeatherForecast), SourceGenerationContext.Default);
            Console.WriteLine(jsonString);
            // output:
            //{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":"Hot"}

            sourceGenOptions = new JsonSerializerOptions
            {
                TypeInfoResolver = SourceGenerationContext.Default
            };

            jsonString = JsonSerializer.Serialize(
                weatherForecast, typeof(WeatherForecast), sourceGenOptions);
            Console.WriteLine(jsonString);
            // output:
            //{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":"Hot"}
        }
    }
}

원본 생성 모드 지정

여러 형식을 포함할 수 있는 전체 컨텍스트에 대해 메타데이터 기반 모드 또는 Serialization 최적화 모드를 지정할 수 있습니다. 또는 개별 형식에 대한 모드를 지정할 수 있습니다. 둘 다 수행하면 형식에 대한 모드 사양이 적용됩니다.

Serialization 최적화(빠른 경로) 모드 예제

  • 전체 컨텍스트의 경우:

    [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Serialization)]
    [JsonSerializable(typeof(WeatherForecast))]
    internal partial class SerializeOnlyContext : JsonSerializerContext
    {
    }
    
  • 개별 형식의 경우:

    [JsonSerializable(typeof(WeatherForecast), GenerationMode = JsonSourceGenerationMode.Serialization)]
    internal partial class SerializeOnlyWeatherForecastOnlyContext : JsonSerializerContext
    {
    }
    
  • 전체 프로그램 예제

    using System.Text.Json;
    using System.Text.Json.Serialization;
    
    namespace SerializeOnlyNoOptions
    {
        public class WeatherForecast
        {
            public DateTime Date { get; set; }
            public int TemperatureCelsius { get; set; }
            public string? Summary { get; set; }
        }
    
        [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Serialization)]
        [JsonSerializable(typeof(WeatherForecast))]
        internal partial class SerializeOnlyContext : JsonSerializerContext
        {
        }
        
        [JsonSerializable(typeof(WeatherForecast), GenerationMode = JsonSourceGenerationMode.Serialization)]
        internal partial class SerializeOnlyWeatherForecastOnlyContext : JsonSerializerContext
        {
        }
    
         public class Program
        {
            public static void Main()
            {
                string jsonString;
                WeatherForecast weatherForecast = new()
                    { Date = DateTime.Parse("2019-08-01"), TemperatureCelsius = 25, Summary = "Hot" };
    
                // Use context that selects Serialization mode only for WeatherForecast.
                jsonString = JsonSerializer.Serialize(weatherForecast,
                    SerializeOnlyWeatherForecastOnlyContext.Default.WeatherForecast);
                Console.WriteLine(jsonString);
                // output:
                //{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":"Hot"}
    
                // Use a context that selects Serialization mode.
                jsonString = JsonSerializer.Serialize(weatherForecast,
                    SerializeOnlyContext.Default.WeatherForecast);
                Console.WriteLine(jsonString);
                // output:
                //{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":"Hot"}
            }
        }
    }
    

메타데이터 기반 모드 예제

  • 전체 컨텍스트의 경우:

    [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)]
    [JsonSerializable(typeof(WeatherForecast))]
    internal partial class MetadataOnlyContext : JsonSerializerContext
    {
    }
    
    jsonString = JsonSerializer.Serialize(
        weatherForecast!, MetadataOnlyContext.Default.WeatherForecast);
    
    weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(
        jsonString, MetadataOnlyContext.Default.WeatherForecast);
    
  • 개별 형식의 경우:

    [JsonSerializable(typeof(WeatherForecast), GenerationMode = JsonSourceGenerationMode.Metadata)]
    internal partial class MetadataOnlyWeatherForecastOnlyContext : JsonSerializerContext
    {
    }
    
    jsonString = JsonSerializer.Serialize(
        weatherForecast!,
        MetadataOnlyWeatherForecastOnlyContext.Default.WeatherForecast);
    
    weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(
        jsonString, MetadataOnlyWeatherForecastOnlyContext.Default.WeatherForecast);
    
  • 전체 프로그램 예제

    using System.Text.Json;
    using System.Text.Json.Serialization;
    
    namespace MetadataOnlyNoOptions
    {
        public class WeatherForecast
        {
            public DateTime Date { get; set; }
            public int TemperatureCelsius { get; set; }
            public string? Summary { get; set; }
        }
    
        [JsonSerializable(typeof(WeatherForecast), GenerationMode = JsonSourceGenerationMode.Metadata)]
        internal partial class MetadataOnlyWeatherForecastOnlyContext : JsonSerializerContext
        {
        }
    
        [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)]
        [JsonSerializable(typeof(WeatherForecast))]
        internal partial class MetadataOnlyContext : JsonSerializerContext
        {
        }
    
        public class Program
        {
            public static void Main()
            {
                string jsonString = """
                    {
                      "Date": "2019-08-01T00:00:00",
                      "TemperatureCelsius": 25,
                      "Summary": "Hot"
                    }
                    """;
                WeatherForecast? weatherForecast;
    
                // Deserialize with context that selects metadata mode only for WeatherForecast only.
                weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(
                    jsonString, MetadataOnlyWeatherForecastOnlyContext.Default.WeatherForecast);
                Console.WriteLine($"Date={weatherForecast?.Date}");
                // output:
                //Date=8/1/2019 12:00:00 AM
    
                // Serialize with context that selects metadata mode only for WeatherForecast only.
                jsonString = JsonSerializer.Serialize(
                    weatherForecast!,
                    MetadataOnlyWeatherForecastOnlyContext.Default.WeatherForecast);
                Console.WriteLine(jsonString);
                // output:
                //{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":"Hot"}
    
                // Deserialize with context that selects metadata mode only.
                weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(
                    jsonString, MetadataOnlyContext.Default.WeatherForecast);
                Console.WriteLine($"Date={weatherForecast?.Date}");
                // output:
                //Date=8/1/2019 12:00:00 AM
    
                // Serialize with context that selects metadata mode only.
                jsonString = JsonSerializer.Serialize(
                    weatherForecast!, MetadataOnlyContext.Default.WeatherForecast);
                Console.WriteLine(jsonString);
                // output:
                //{"Date":"2019-08-01T00:00:00","TemperatureCelsius":0,"Summary":"Hot"}
            }
        }
    }
    

ASP.NET Core의 원본 생성 지원

Blazor 앱에서는 원본 생성 컨텍스트 또는 TypeInfo<TValue>를 사용하는 HttpClientJsonExtensions.GetFromJsonAsyncHttpClientJsonExtensions.PostAsJsonAsync 확장 메서드의 오버로드를 사용합니다.

.NET 8부터 원본 생성 컨텍스트를 또는 TypeInfo<TValue>를 허용하는 HttpClientJsonExtensions.GetFromJsonAsAsyncEnumerable 확장 메서드의 오버로드를 사용할 수도 있습니다.

Razor Pages, MVC, SignalR, Web API 앱에서 JsonSerializerOptions.TypeInfoResolver 속성을 사용하여 컨텍스트를 지정합니다.

[JsonSerializable(typeof(WeatherForecast[]))]
internal partial class MyJsonContext : JsonSerializerContext { }
var serializerOptions = new JsonSerializerOptions
{
    TypeInfoResolver = MyJsonContext.Default
};

services.AddControllers().AddJsonOptions(
    static options =>
        options.JsonSerializerOptions.TypeInfoResolverChain.Add(MyJsonContext.Default));

Razor Pages, MVC, SignalR, Web API 앱에서 JsonSerializerOptions.TypeInfoResolver 속성을 사용하여 컨텍스트를 지정합니다.

[JsonSerializable(typeof(WeatherForecast[]))]
internal partial class MyJsonContext : JsonSerializerContext { }
var serializerOptions = new JsonSerializerOptions
{
    TypeInfoResolver = MyJsonContext.Default
};

services.AddControllers().AddJsonOptions(
    static options =>
        options.JsonSerializerOptions = serializerOptions);

Razor Pages, MVC, SignalR, Web API 앱에서 다음 예제와 같이 JsonSerializerOptionsAddContext 메서드를 사용합니다.

[JsonSerializable(typeof(WeatherForecast[]))]
internal partial class MyJsonContext : JsonSerializerContext { }
services.AddControllers().AddJsonOptions(options =>
    options.JsonSerializerOptions.AddContext<MyJsonContext>());

참고 항목

JsonSourceGenerationMode.Serialization 또는 빠른 경로 Serialization은 비동기 Serialization에 지원되지 않습니다.

.NET 7 및 이전 버전에서는 이 제한이 Stream을 허용하는 JsonSerializer.Serialize의 동기 오버로드에도 적용됩니다. .NET 8부터 스트리밍 직렬화에는 메타데이터 기반 모델이 필요하지만 페이로드가 미리 결정된 버퍼 크기에 맞을 만큼 충분히 작은 것으로 알려진 경우 빠른 경로로 대체됩니다. 자세한 내용은 https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-8/#json를 참조하세요.

리플렉션 기본값 사용 안 함

System.Text.Json은 기본적으로 리플렉션을 사용하므로 기본 Serialization 메서드를 호출하면 필수 리플렉션 API를 모두 지원하지 않는 네이티브 AOT 앱이 중단될 수 있습니다. 이러한 중단은 예측할 수 없기 때문에 진단하기 어려울 수 있으며 리플렉션이 작동하는 CoreCLR 런타임을 사용하여 앱이 디버그되는 경우가 많습니다. 대신 리플렉션 기반 Serialization을 명시적으로 사용하지 않도록 설정하면 중단을 진단하기가 더 쉽습니다. 리플렉션 기반 Serialization을 사용하는 코드는 설명 메시지와 함께 InvalidOperationException이 런타임에 throw됩니다.

앱에서 기본 리플렉션을 사용하지 않도록 설정하려면 프로젝트 파일에서 JsonSerializerIsReflectionEnabledByDefault MSBuild 속성을 false로 설정합니다.

<PropertyGroup>
  <JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
</PropertyGroup>
  • 이 속성의 동작은 런타임(CoreCLR 또는 Native AOT)에 관계없이 일관됩니다.
  • 이 속성을 지정하지 않고 PublishTrimmed가 활성화된 경우 리플렉션 기반 Serialization이 자동으로 비활성화됩니다.

JsonSerializer.IsReflectionEnabledByDefault 속성을 사용하여 리플렉션이 비활성화되었는지 프로그래밍 방식으로 확인할 수 있습니다. 다음 코드 조각은 리플렉션이 사용되는지 여부에 따라 직렬 변환기를 구성하는 방법을 보여 줍니다.

static JsonSerializerOptions CreateDefaultOptions()
{
    return new()
    {
        TypeInfoResolver = JsonSerializer.IsReflectionEnabledByDefault
            ? new DefaultJsonTypeInfoResolver()
            : MyContext.Default
    };
}

속성은 링크 타임 상수로 처리되므로 이전 방법을 네이티브 AOT에서 실행되는 애플리케이션에서 리플렉션 기반 확인자를 루트하지 않습니다.

옵션 지정

.NET 8 이상 버전에서는 JsonSerializerOptions 특성을 사용하여 설정할 수 있는 대부분의 옵션을 JsonSourceGenerationOptionsAttribute 특성을 사용하여 설정할 수도 있습니다. 특성을 통해 옵션을 설정하는 것의 이점은 구성이 컴파일 시간에 지정되어 생성된 MyContext.Default 속성이 모든 관련 옵션 집합으로 미리 구성되도록 한다는 것입니다.

다음 코드에서는 JsonSourceGenerationOptionsAttribute 특성을 사용하여 옵션을 설정하는 방법을 보여 줍니다.

[JsonSourceGenerationOptions(
    WriteIndented = true,
    PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
    GenerationMode = JsonSourceGenerationMode.Serialization)]
[JsonSerializable(typeof(WeatherForecast))]
internal partial class SerializationModeOptionsContext : JsonSerializerContext
{
}

JsonSourceGenerationOptionsAttribute를 사용하여 serialization 옵션을 지정하는 경우 다음 serialization 메서드 중 하나를 호출합니다.

  • TypeInfo<TValue>를 사용하는 JsonSerializer.Serialize 메서드. 컨텍스트 클래스의 Default.<TypeName> 속성을 전달합니다.

    jsonString = JsonSerializer.Serialize(
        weatherForecast, SerializationModeOptionsContext.Default.WeatherForecast);
    
  • 컨텍스트를 사용하는 JsonSerializer.Serialize 메서드. 컨텍스트 클래스의 Default 정적 속성을 전달합니다.

    jsonString = JsonSerializer.Serialize(
        weatherForecast, typeof(WeatherForecast), SerializationModeOptionsContext.Default);
    

고유한 Utf8JsonWriter 인스턴스를 전달할 수 있는 메서드를 호출하는 경우 작성기의 Indented 설정이 JsonSourceGenerationOptionsAttribute.WriteIndented 옵션 대신 적용됩니다.

JsonSerializerOptions 인스턴스를 사용하는 생성자를 호출하여 컨텍스트 인스턴스를 만들고 사용하는 경우 제공된 인스턴스는 JsonSourceGenerationOptionsAttribute에서 지정한 옵션 대신 사용됩니다.

다음은 전체 프로그램에서 앞에 나온 예제입니다.

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

namespace SerializeOnlyWithOptions
{
    public class WeatherForecast
    {
        public DateTime Date { get; set; }
        public int TemperatureCelsius { get; set; }
        public string? Summary { get; set; }
    }

    [JsonSourceGenerationOptions(
        WriteIndented = true,
        PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
        GenerationMode = JsonSourceGenerationMode.Serialization)]
    [JsonSerializable(typeof(WeatherForecast))]
    internal partial class SerializationModeOptionsContext : JsonSerializerContext
    {
    }
    public class Program
    {
        public static void Main()
        {
            string jsonString;
            WeatherForecast weatherForecast = new()
                { Date = DateTime.Parse("2019-08-01"), TemperatureCelsius = 25, Summary = "Hot" };

            // Serialize using TypeInfo<TValue> provided by the context
            // and options specified by [JsonSourceGenerationOptions].
            jsonString = JsonSerializer.Serialize(
                weatherForecast, SerializationModeOptionsContext.Default.WeatherForecast);
            Console.WriteLine(jsonString);
            // output:
            //{
            //  "date": "2019-08-01T00:00:00",
            //  "temperatureCelsius": 0,
            //  "summary": "Hot"
            //}

            // Serialize using Default context
            // and options specified by [JsonSourceGenerationOptions].
            jsonString = JsonSerializer.Serialize(
                weatherForecast, typeof(WeatherForecast), SerializationModeOptionsContext.Default);
            Console.WriteLine(jsonString);
            // output:
            //{
            //  "date": "2019-08-01T00:00:00",
            //  "temperatureCelsius": 0,
            //  "summary": "Hot"
            //}
        }
    }
}

JsonSerializerOptions를 사용하여 옵션 지정

JsonSerializerOptions의 일부 옵션은 JsonSourceGenerationOptionsAttribute를 사용하여 설정할 수 없습니다. JsonSerializerOptions를 사용하여 옵션을 지정하려면 다음을 수행합니다.

  • JsonSerializerOptions의 인스턴스를 만듭니다.
  • JsonSerializerContext에서 파생되는 클래스의 인스턴스를 만들고 JsonSerializerOptions 인스턴스를 생성자에 전달합니다.
  • 컨텍스트 인스턴스 또는 TypeInfo<TValue>를 사용하는 JsonSerializer의 serialization 또는 deserialization 메서드를 호출합니다.

다음은 예제 컨텍스트 클래스와 serialization 및 deserialization 예제 코드입니다.

[JsonSerializable(typeof(WeatherForecast))]
internal partial class OptionsExampleContext : JsonSerializerContext
{
}
jsonString = JsonSerializer.Serialize(
    weatherForecast,
    typeof(WeatherForecast),
    new OptionsExampleContext(
        new JsonSerializerOptions(JsonSerializerDefaults.Web)));
weatherForecast = JsonSerializer.Deserialize(
    jsonString, 
    typeof(WeatherForecast), 
    new OptionsExampleContext(
        new JsonSerializerOptions(JsonSerializerDefaults.Web)))
        as WeatherForecast;

다음은 전체 프로그램에서 앞에 나온 예제입니다.

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

namespace JsonSerializerOptionsExample
{
    public class WeatherForecast
    {
        public DateTime Date { get; set; }
        public int TemperatureCelsius { get; set; }
        public string? Summary { get; set; }
    }

    [JsonSerializable(typeof(WeatherForecast))]
    internal partial class OptionsExampleContext : JsonSerializerContext
    {
    }

    public class Program
    {
        public static void Main()
        {
            string jsonString = """
                {
                  "date": "2019-08-01T00:00:00",
                  "temperatureCelsius": 25,
                  "summary": "Hot"
                }
                """;
            WeatherForecast? weatherForecast;

            weatherForecast = JsonSerializer.Deserialize(
                jsonString, 
                typeof(WeatherForecast), 
                new OptionsExampleContext(
                    new JsonSerializerOptions(JsonSerializerDefaults.Web)))
                    as WeatherForecast;
            Console.WriteLine($"Date={weatherForecast?.Date}");
            // output:
            //Date=8/1/2019 12:00:00 AM

            jsonString = JsonSerializer.Serialize(
                weatherForecast,
                typeof(WeatherForecast),
                new OptionsExampleContext(
                    new JsonSerializerOptions(JsonSerializerDefaults.Web)));
            Console.WriteLine(jsonString);
            // output:
            //{ "date":"2019-08-01T00:00:00","temperatureCelsius":25,"summary":"Hot"}
        }
    }
}

원본 생성기 결합

단일 JsonSerializerOptions 인스턴스 내에서 여러 원본 생성 컨텍스트의 계약을 결합할 수 있습니다. JsonTypeInfoResolver.Combine(IJsonTypeInfoResolver[]) 메서드를 사용하여 결합된 여러 컨텍스트를 연결하려면 JsonSerializerOptions.TypeInfoResolver 속성을 사용합니다.

var options = new JsonSerializerOptions
{
    TypeInfoResolver = JsonTypeInfoResolver.Combine(ContextA.Default, ContextB.Default, ContextC.Default);
};

.NET 8부터 나중에 다른 컨텍스트를 앞이나 뒤에 추가하려는 경우 JsonSerializerOptions.TypeInfoResolverChain 속성을 사용하면 됩니다. 체인의 순서는 중요합니다. JsonSerializerOptions는 각 확인자를 지정된 순서로 쿼리하고 null이 아닌 첫 번째 결과를 반환합니다.

options.TypeInfoResolverChain.Add(ContextD.Default); // Append to the end of the list.
options.TypeInfoResolverChain.Insert(0, ContextE.Default); // Insert at the beginning of the list.

TypeInfoResolverChain 속성에 대한 모든 변경 내용은 TypeInfoResolver에 반영되며 그 반대의 경우도 마찬가지입니다.

열거형 필드를 문자열로 직렬화

기본적으로 열거형은 숫자로 직렬화됩니다. 원본 생성을 사용할 때 특정 열거형의 필드를 문자열로 직렬화하려면 JsonStringEnumConverter<TEnum> 변환기로 주석을 추가합니다. 또는 모든 열거형에 대해 포괄 정책을 설정하려면 JsonSourceGenerationOptionsAttribute 특성을 사용합니다.

JsonStringEnumConverter<T> 변환기

원본 생성을 사용하여 열거형 이름을 문자열로 직렬화하려면 JsonStringEnumConverter<TEnum> 변환기를 사용합니다. (제네릭이 아닌 JsonStringEnumConverter 형식은 네이티브 AOT 런타임에서 지원되지 않습니다.)

JsonConverterAttribute 특성을 사용하여 JsonStringEnumConverter<TEnum> 변환기로 열거형 형식에 주석을 추가합니다.

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
}

JsonSerializerContext 클래스를 만들고 JsonSerializableAttribute 특성으로 주석을 추가합니다.

[JsonSerializable(typeof(WeatherForecastWithPrecipEnum))]
public partial class Context1 : JsonSerializerContext { }

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

var weatherForecast = new WeatherForecastWithPrecipEnum
{
    Date = DateTime.Parse("2019-08-01"),
    TemperatureCelsius = 25,
    Precipitation = Precipitation.Sleet
};

var options = new JsonSerializerOptions
{
    WriteIndented = true,
    TypeInfoResolver = Context1.Default,
};
string? jsonString = JsonSerializer.Serialize(weatherForecast, options);

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

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

포괄 정책

JsonStringEnumConverter<TEnum> 형식을 사용하는 대신 JsonSourceGenerationOptionsAttribute를 사용하여 열거형을 문자열로 직렬화하는 포괄 정책을 적용할 수 있습니다. JsonSerializerContext 클래스를 만들고 JsonSerializableAttributeJsonSourceGenerationOptionsAttribute 특성으로 주석을 추가합니다.

[JsonSourceGenerationOptions(UseStringEnumConverter = true)]
[JsonSerializable(typeof(WeatherForecast2WithPrecipEnum))]
public partial class Context2 : JsonSerializerContext { }

열거형에는 JsonConverterAttribute가 없습니다.

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

public enum Precipitation2
{
    Drizzle, Rain, Sleet, Hail, Snow
}

참고 항목