Skip to content

Commit cf12d96

Browse files
authored
Tweak configuration of JsonSerializerOptions (#49875)
1 parent ec3722f commit cf12d96

File tree

52 files changed

+396
-192
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+396
-192
lines changed

src/Http/Http.Extensions/gen/RequestDelegateGeneratorSources.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ private static Func<HttpContext, StringValues> ResolveFromRouteOrQuery(string pa
188188
""";
189189

190190
public static string ResolveJsonBodyOrServiceMethod => """
191-
private static Func<HttpContext, bool, ValueTask<(bool, T?)>> ResolveJsonBodyOrService<T>(LogOrThrowExceptionHelper logOrThrowExceptionHelper, string parameterTypeName, string parameterName, JsonOptions jsonOptions, IServiceProviderIsService? serviceProviderIsService = null)
191+
private static Func<HttpContext, bool, ValueTask<(bool, T?)>> ResolveJsonBodyOrService<T>(LogOrThrowExceptionHelper logOrThrowExceptionHelper, string parameterTypeName, string parameterName, JsonSerializerOptions jsonSerializerOptions, IServiceProviderIsService? serviceProviderIsService = null)
192192
{
193193
if (serviceProviderIsService is not null)
194194
{
@@ -197,7 +197,7 @@ private static Func<HttpContext, StringValues> ResolveFromRouteOrQuery(string pa
197197
return static (httpContext, isOptional) => new ValueTask<(bool, T?)>((true, httpContext.RequestServices.GetService<T>()));
198198
}
199199
}
200-
var jsonTypeInfo = (JsonTypeInfo<T>)jsonOptions.SerializerOptions.GetTypeInfo(typeof(T));
200+
var jsonTypeInfo = (JsonTypeInfo<T>)jsonSerializerOptions.GetTypeInfo(typeof(T));
201201
return (httpContext, isOptional) => TryResolveBodyAsync<T>(httpContext, logOrThrowExceptionHelper, isOptional, parameterTypeName, parameterName, jsonTypeInfo, isInferred: true);
202202
}
203203
""";
@@ -506,6 +506,7 @@ namespace Microsoft.AspNetCore.Http.Generated
506506
{{GeneratedCodeAttribute}}
507507
file static class GeneratedRouteBuilderExtensionsCore
508508
{
509+
private static readonly JsonOptions FallbackJsonOptions = new();
509510
{{GetVerbs(verbs)}}
510511
{{endpoints}}
511512

src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EndpointEmitter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ static void ProcessParameter(EndpointParameter parameter, CodeWriter codeWriter,
115115
}
116116
codeWriter.Write($@"var {parameter.SymbolName}_JsonBodyOrServiceResolver = ");
117117
var shortParameterTypeName = parameter.Type.ToDisplayString(SymbolDisplayFormat.CSharpShortErrorMessageFormat);
118-
codeWriter.WriteLine($"ResolveJsonBodyOrService<{parameter.Type.ToDisplayString(EmitterConstants.DisplayFormat)}>(logOrThrowExceptionHelper, {SymbolDisplay.FormatLiteral(shortParameterTypeName, true)}, {SymbolDisplay.FormatLiteral(parameter.SymbolName, true)}, jsonOptions, serviceProviderIsService);");
118+
codeWriter.WriteLine($"ResolveJsonBodyOrService<{parameter.Type.ToDisplayString(EmitterConstants.DisplayFormat)}>(logOrThrowExceptionHelper, {SymbolDisplay.FormatLiteral(shortParameterTypeName, true)}, {SymbolDisplay.FormatLiteral(parameter.SymbolName, true)}, jsonSerializerOptions, serviceProviderIsService);");
119119
}
120120
}
121121
}

src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EndpointJsonPreparationEmitter.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ internal static class EndpointJsonPreparationEmitter
88
{
99
internal static void EmitJsonPreparation(this Endpoint endpoint, CodeWriter codeWriter)
1010
{
11-
codeWriter.WriteLine("var jsonOptions = serviceProvider?.GetService<IOptions<JsonOptions>>()?.Value ?? new JsonOptions();");
12-
codeWriter.WriteLine($"var objectJsonTypeInfo = (JsonTypeInfo<object?>)jsonOptions.SerializerOptions.GetTypeInfo(typeof(object));");
11+
codeWriter.WriteLine("var jsonOptions = serviceProvider?.GetService<IOptions<JsonOptions>>()?.Value ?? FallbackJsonOptions;");
12+
codeWriter.WriteLine("var jsonSerializerOptions = jsonOptions.SerializerOptions;");
13+
codeWriter.WriteLine("jsonSerializerOptions.MakeReadOnly();");
14+
codeWriter.WriteLine($"var objectJsonTypeInfo = (JsonTypeInfo<object?>)jsonSerializerOptions.GetTypeInfo(typeof(object));");
1315

1416
if (endpoint.Response?.IsSerializableJsonResponse(out var responseType) == true)
1517
{
1618
var typeName = responseType.ToDisplayString(EmitterConstants.DisplayFormatWithoutNullability);
17-
codeWriter.WriteLine($"var responseJsonTypeInfo = (JsonTypeInfo<{responseType.ToDisplayString(NullableFlowState.MaybeNull, EmitterConstants.DisplayFormat)}>)jsonOptions.SerializerOptions.GetTypeInfo(typeof({typeName}));");
19+
codeWriter.WriteLine($"var responseJsonTypeInfo = (JsonTypeInfo<{responseType.ToDisplayString(NullableFlowState.MaybeNull, EmitterConstants.DisplayFormat)}>)jsonSerializerOptions.GetTypeInfo(typeof({typeName}));");
1820
}
1921

2022
foreach (var parameter in endpoint.Parameters)
@@ -36,7 +38,7 @@ static void ProcessParameter(EndpointParameter parameter, CodeWriter codeWriter)
3638
return;
3739
}
3840
var typeName = parameter.Type.ToDisplayString(EmitterConstants.DisplayFormat);
39-
codeWriter.WriteLine($"var {parameter.SymbolName}_JsonTypeInfo = (JsonTypeInfo<{typeName}>)jsonOptions.SerializerOptions.GetTypeInfo(typeof({parameter.Type.ToDisplayString(EmitterConstants.DisplayFormatWithoutNullability)}));");
41+
codeWriter.WriteLine($"var {parameter.SymbolName}_JsonTypeInfo = (JsonTypeInfo<{typeName}>)jsonSerializerOptions.GetTypeInfo(typeof({parameter.Type.ToDisplayString(EmitterConstants.DisplayFormatWithoutNullability)}));");
4042
}
4143

4244
}

src/Http/Http.Extensions/src/JsonOptions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ public class JsonOptions
2323

2424
// The JsonSerializerOptions.GetTypeInfo method is called directly and needs a defined resolver
2525
// setting the default resolver (reflection-based) but the user can overwrite it directly or by modifying
26-
// the TypeInfoResolverChain
27-
TypeInfoResolver = JsonSerializer.IsReflectionEnabledByDefault ? CreateDefaultTypeResolver() : null
26+
// the TypeInfoResolverChain. Use JsonTypeInfoResolver.Combine() to produce an empty TypeInfoResolver.
27+
TypeInfoResolver = JsonSerializer.IsReflectionEnabledByDefault ? CreateDefaultTypeResolver() : JsonTypeInfoResolver.Combine()
2828
};
2929

3030
// Use a copy so the defaults are not modified.

src/Http/Http.Extensions/test/JsonOptionsTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public class JsonOptionsTests
1212
{
1313
[ConditionalFact]
1414
[RemoteExecutionSupported]
15-
public void DefaultSerializerOptions_SetsTypeInfoResolverNull_WhenJsonIsReflectionEnabledByDefaultFalse()
15+
public void DefaultSerializerOptions_SetsTypeInfoResolverEmptyResolver_WhenJsonIsReflectionEnabledByDefaultFalse()
1616
{
1717
var options = new RemoteInvokeOptions();
1818
options.RuntimeConfigurationOptions.Add("System.Text.Json.JsonSerializer.IsReflectionEnabledByDefault", false.ToString());
@@ -23,7 +23,8 @@ public void DefaultSerializerOptions_SetsTypeInfoResolverNull_WhenJsonIsReflecti
2323
var options = JsonOptions.DefaultSerializerOptions;
2424

2525
// Assert
26-
Assert.Null(options.TypeInfoResolver);
26+
Assert.NotNull(options.TypeInfoResolver);
27+
Assert.IsAssignableFrom<IJsonTypeInfoResolver>(options.TypeInfoResolver);
2728
}, options);
2829
}
2930

src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/HandlesEndpointsWithAndWithoutDiagnostics.generated.txt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ namespace Microsoft.AspNetCore.Http.Generated
5555
%GENERATEDCODEATTRIBUTE%
5656
file static class GeneratedRouteBuilderExtensionsCore
5757
{
58+
private static readonly JsonOptions FallbackJsonOptions = new();
5859
private static readonly string[] GetVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Get };
5960

6061
[InterceptsLocation(@"TestMapActions.cs", 9, 13)]
@@ -80,8 +81,10 @@ namespace Microsoft.AspNetCore.Http.Generated
8081
var handler = Cast(del, global::System.String () => throw null!);
8182
EndpointFilterDelegate? filteredInvocation = null;
8283
var serviceProvider = options.ServiceProvider ?? options.EndpointBuilder.ApplicationServices;
83-
var jsonOptions = serviceProvider?.GetService<IOptions<JsonOptions>>()?.Value ?? new JsonOptions();
84-
var objectJsonTypeInfo = (JsonTypeInfo<object?>)jsonOptions.SerializerOptions.GetTypeInfo(typeof(object));
84+
var jsonOptions = serviceProvider?.GetService<IOptions<JsonOptions>>()?.Value ?? FallbackJsonOptions;
85+
var jsonSerializerOptions = jsonOptions.SerializerOptions;
86+
jsonSerializerOptions.MakeReadOnly();
87+
var objectJsonTypeInfo = (JsonTypeInfo<object?>)jsonSerializerOptions.GetTypeInfo(typeof(object));
8588

8689
if (options.EndpointBuilder.FilterFactories.Count > 0)
8790
{

src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_BindAsync_NullableReturn.generated.txt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ namespace Microsoft.AspNetCore.Http.Generated
5555
%GENERATEDCODEATTRIBUTE%
5656
file static class GeneratedRouteBuilderExtensionsCore
5757
{
58+
private static readonly JsonOptions FallbackJsonOptions = new();
5859
private static readonly string[] GetVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Get };
5960

6061
[InterceptsLocation(@"TestMapActions.cs", 25, 13)]
@@ -82,8 +83,10 @@ namespace Microsoft.AspNetCore.Http.Generated
8283
EndpointFilterDelegate? filteredInvocation = null;
8384
var serviceProvider = options.ServiceProvider ?? options.EndpointBuilder.ApplicationServices;
8485
var logOrThrowExceptionHelper = new LogOrThrowExceptionHelper(serviceProvider, options);
85-
var jsonOptions = serviceProvider?.GetService<IOptions<JsonOptions>>()?.Value ?? new JsonOptions();
86-
var objectJsonTypeInfo = (JsonTypeInfo<object?>)jsonOptions.SerializerOptions.GetTypeInfo(typeof(object));
86+
var jsonOptions = serviceProvider?.GetService<IOptions<JsonOptions>>()?.Value ?? FallbackJsonOptions;
87+
var jsonSerializerOptions = jsonOptions.SerializerOptions;
88+
jsonSerializerOptions.MakeReadOnly();
89+
var objectJsonTypeInfo = (JsonTypeInfo<object?>)jsonSerializerOptions.GetTypeInfo(typeof(object));
8790
var parameters = del.Method.GetParameters();
8891

8992
if (options.EndpointBuilder.FilterFactories.Count > 0)
@@ -188,8 +191,10 @@ namespace Microsoft.AspNetCore.Http.Generated
188191
EndpointFilterDelegate? filteredInvocation = null;
189192
var serviceProvider = options.ServiceProvider ?? options.EndpointBuilder.ApplicationServices;
190193
var logOrThrowExceptionHelper = new LogOrThrowExceptionHelper(serviceProvider, options);
191-
var jsonOptions = serviceProvider?.GetService<IOptions<JsonOptions>>()?.Value ?? new JsonOptions();
192-
var objectJsonTypeInfo = (JsonTypeInfo<object?>)jsonOptions.SerializerOptions.GetTypeInfo(typeof(object));
194+
var jsonOptions = serviceProvider?.GetService<IOptions<JsonOptions>>()?.Value ?? FallbackJsonOptions;
195+
var jsonSerializerOptions = jsonOptions.SerializerOptions;
196+
jsonSerializerOptions.MakeReadOnly();
197+
var objectJsonTypeInfo = (JsonTypeInfo<object?>)jsonSerializerOptions.GetTypeInfo(typeof(object));
193198
var parameters = del.Method.GetParameters();
194199

195200
if (options.EndpointBuilder.FilterFactories.Count > 0)

0 commit comments

Comments
 (0)