-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Closed
Labels
api-approvedAPI was approved in API review, it can be implementedAPI was approved in API review, it can be implementedarea-System.Text.JsonblockingMarks issues that we want to fast track in order to unblock other important workMarks issues that we want to fast track in order to unblock other important work
Milestone
Description
Background and motivation
When shipped in .NET 7, the contract customization feature added support for chaining resolvers by means of the JsonTypeInfoResolver.Combine method:
var options = new JsonTypeInfoResolver
{
TypeInfoResolver = JsonTypeInfoResolver.Combine(ContextA.Default, ContextB.Default, ContextC.Default);
};Based on feedback we've received, this approach has a couple of usability issues:
- It necessitates specifying all chained components at one call site -- resolvers cannot be prepended or appended to the chain after the fact.
- Because the chaining implementation is abstracted behind a
IJsonTypeInfoResolverimplementation, there is no way for users to introspect the chain or remove components from it.
API Proposal
namespace System.Text.Json;
public partial class JsonSerializerOptions
{
public IJsonTypeInfoResolver? TypeInfoResolver { get; set; }
+ public IList<IJsonTypeInfoResolver> TypeInfoResolverChain { get; }
}With this API added, we should also revert the recent change to AddContext in #80698 since it provided an inadequate attempt to address the same underlying issue:
- It only allows appending resolvers, prepending is not possible
- It only works with JsonSerializerContext, not resolvers in general.
- It introduces a breaking change compared to the
AddContextmethod in .NET 7.
API Usage
The new property should complement and be mutually consistent with the existing TypeInfoResolver property. Here are a few examples:
Setting a resolver to TypeInfoResolver
JsonSerializerOptions options = new();
options.TypeInfoResolver = new DefaultJsonTypeInfoResolver();
Assert.Equal(new IJsonTypeInfoResolver[] { options.TypeInfoResolver }, options.ChainedTypeInfoResolvers);Setting a combined resolver to TypeInfoResolver
JsonSerializerOptions options = new();
options.TypeInfoResolver = JsonTypeInfoResolver.Combine(CtxA.Default, CtxB.Default, CtxC.Default);
Assert.Equal(new IJsonTypeInfoResolver[] { CtxA.Default, CtxB.Default, CtxC.Default }, options.ChainedTypeInfoResolvers);
Assert.Same(options.TypeInfoResolver, options.ChainedTypeInfoResolvers);Appending a resolver to ChainedTypeInfoResolvers
JsonSerializerOptions options = new();
options.ChainedTypeInfoResolvers.Add(CtxA.Default);
options.ChainedTypeInfoResolvers.Add(CtxB.Default);
options.ChainedTypeInfoResolvers.Add(CtxC.Default);
Assert.Equal(new IJsonTypeInfoResolver[] { CtxA.Default, CtxB.Default, CtxC.Default }, options.ChainedTypeInfoResolvers);
Assert.Same(options.TypeInfoResolver, options.ChainedTypeInfoResolvers);Prepending a resolver to ChainedTypeInfoResolvers:
JsonSerializerOptions options = new();
DefaultJsonTypeInfoResolver defaultResolver = new();
options.TypeInfoResolver = defaultResolver ;
Assert.Equal(new IJsonTypeInfoResolver[] { defaultResolver }, options.ChainedTypeInfoResolvers);
options.ChainedTypeInfoResolvers.Insert(0, CtxA.Default);
Assert.Equal(new IJsonTypeInfoResolver[] { CtxA.Default, defaultResolver }, options.ChainedTypeInfoResolvers);Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
api-approvedAPI was approved in API review, it can be implementedAPI was approved in API review, it can be implementedarea-System.Text.JsonblockingMarks issues that we want to fast track in order to unblock other important workMarks issues that we want to fast track in order to unblock other important work