System.Text.Json 원본 생성기 대체

JsonSerializerOptions를 허용하는 JsonSerializer 메서드 중 하나를 사용하는 경우 System.Text.Json 원본 생성기는 더 이상 인식할 수 없는 형식에 대한 리플렉션 기반 serialization으로 암시적으로 대체되지 않습니다.

이전 동작

.NET 6에서 다음 원본 생성 예제를 고려해 보세요.

JsonSerializer.Serialize(new Poco2(), typeof(Poco2), MyContext.Default);

[JsonSerializable(typeof(Poco1))]
public partial class MyContext : JsonSerializerContext {}

public class Poco1 { }
public class Poco2 { }

MyContext에는 직렬화 가능한 형식의 Poco2가 포함되지 않으므로 다음 예외를 나타내며 serialization이 올바르게 실패합니다.

System.InvalidOperationException:

'Metadata for type 'Poco2' was not provided to the serializer. The serializer method used does not 
support reflection-based creation of serialization-related type metadata. If using source generation, 
ensure that all root types passed to the serializer have been indicated with 'JsonSerializableAttribute', 
along with any types that might be serialized polymorphically.

이제 원본 생성기에서 생성된 JsonSerializerOptions 인스턴스를 사용하여 동일한 형식(MyContext)을 직렬화하려고 시도하는 다음 호출을 고려합니다.

JsonSerializer.Serialize(new Poco2(), MyContext.Default.Options);

옵션 인스턴스는 자동으로 기본 리플렉션 기반 계약 확인자를 대체 메커니즘으로 통합하므로 해당 형식이 리플렉션을 사용하여 성공적으로 직렬화됩니다.

JsonSerializerContext에 연결된 옵션 인스턴스에 대해 동일한 대체 논리가 JsonSerializerOptions.GetConverter(Type)에 적용됩니다. 다음 문은 기본 제공 리플렉션 변환기를 사용하여 변환기를 반환합니다.

JsonConverter converter = MyContext.Default.Options.GetConverter(typeof(Poco2));

새 동작

.NET 7부터 다음 호출은 JsonSerializerContext 오버로드를 사용할 때와 동일한 예외(InvalidOperationException)를 나타내며 실패합니다.

JsonSerializer.Serialize(new Poco2(), MyContext.Default.Options);

또한 다음 문은 NotSupportedException을 나타내며 실패합니다.

JsonConverter converter = MyContext.Default.Options.GetConverter(typeof(Poco2));

도입된 버전

.NET 7

호환성이 손상되는 변경의 형식

이 변경은 이진 호환성에 영향을 줄 수 있습니다.

변경 이유

이전 동작은 최소 놀람의 원칙을 위반하며 궁극적으로 소스 생성이라는 목적에서 벗어납니다. 형식의 JSON serialization 계약을 사용자 지정할 수 있는 기능이 출시되면서 계약 메타데이터의 원본을 미세 조정할 수 있습니다. 이 점을 염두에 둔다면, 대체 소스를 자동으로 도입하는 것은 별로 바람직하지 않습니다.

의도적으로 또는 의도치 않게 이전 동작에 의존할 수 있습니다. 권장되는 작업 과정은 모든 형식 종속성을 포함하도록 JsonSerializerContext 정의를 업데이트하는 것입니다.

[JsonSerializable(typeof(Poco1))]
[JsonSerializable(typeof(Poco2))]
public partial class MyContext : JsonSerializerContext {}

이렇게 하면 애플리케이션이 트리밍 안전성 등과 같은 원본 생성의 이점을 최대한 활용할 수 있습니다.

그러나 어떤 경우에는 이렇게 변경하는 것이 실용적이지 않거나 가능하지 않을 수 있습니다. 권장되지는 않지만 소스 생성 직렬 변환기에서 리플렉션 대체를 다시 사용하도록 설정할 수 있는 몇 가지 방법이 있습니다.

사용자 지정 계약 확인자 사용

새 계약 사용자 지정 기능을 사용하여 필요한 경우 리플렉션 기반 확인으로 되돌아가는 사용자 지정 계약 확인자를 빌드할 수 있습니다.

var options = new JsonSerializerOptions
{
     TypeInfoResolver = JsonTypeInfoResolver.Combine(MyContext.Default, new DefaultJsonTypeInfoResolver());
}

JsonSerializer.Serialize(new Poco2(), options); // Contract resolution falls back to the default reflection-based resolver.
options.GetConverter(typeof(Poco2)); // Returns the reflection-based converter.

AppContext 스위치 사용

.NET 7부터 제공된 AppContext 호환성 스위치를 사용하여 리플렉션 대체를 전역적으로 다시 사용하도록 설정할 수 있습니다. 애플리케이션의 프로젝트 파일에 다음 항목을 추가하여 앱의 모든 원본 생성 컨텍스트에 대한 리플렉션 대체를 다시 사용하도록 설정합니다. AppContext 스위치 사용에 대한 자세한 내용은 .NET 런타임 구성 설정 문서를 참조하세요.

<ItemGroup>
  <RuntimeHostConfigurationOption Include="System.Text.Json.Serialization.EnableSourceGenReflectionFallback" Value="true" />
</ItemGroup>

영향을 받는 API