Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing reflection-based json configuration #46303

Closed
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
c2945c2
Mvc JsonOptions updates
brunolins16 Jan 26, 2023
26be191
Http JsonOptions updates
brunolins16 Jan 26, 2023
5754198
Merge remote-tracking branch 'upstream/main' into brunolins16/aot/jso…
brunolins16 Jan 26, 2023
b6fadd9
Bad merge
brunolins16 Jan 26, 2023
d31a8e2
fix end line
brunolins16 Jan 26, 2023
cc71ed2
Updating RUC/RDC message
brunolins16 Jan 26, 2023
f47a076
Add call to AddRouting
brunolins16 Jan 27, 2023
d227b30
Fix suppressions
brunolins16 Jan 27, 2023
df207a0
Remove empty spaces
brunolins16 Jan 27, 2023
9e97941
Moving to Routing
brunolins16 Jan 28, 2023
eb64558
Revert "Moving to Routing"
brunolins16 Jan 30, 2023
5b175ed
Adding AddDefaultJsonOptions API
brunolins16 Jan 30, 2023
45b2282
Fixing unit tests
brunolins16 Jan 31, 2023
bb507c7
Trying a different approach
brunolins16 Jan 31, 2023
f52c535
Changing MVC
brunolins16 Jan 31, 2023
4298afc
Clean up
brunolins16 Feb 1, 2023
785d91e
Merge remote-tracking branch 'upstream/main' into brunolins16/aot/jso…
brunolins16 Feb 1, 2023
60f9ade
Clean up & Fix/Add unit tests
brunolins16 Feb 1, 2023
df95bd3
Merge remote-tracking branch 'upstream/main' into brunolins16/aot/jso…
brunolins16 Feb 1, 2023
b9ec639
Merge remote-tracking branch 'upstream/main' into brunolins16/aot/jso…
brunolins16 Feb 1, 2023
e186cc4
Include TrimmingAppContextSwitches
brunolins16 Feb 1, 2023
de59eb6
Create Microsoft.AspNetCore.Http.Results.WarningSuppressions.xml
brunolins16 Feb 2, 2023
2f2869a
Clean up
brunolins16 Feb 2, 2023
c45a8f3
Merging changes from #46225
brunolins16 Feb 3, 2023
de450ae
Locking JsonOptions :(
brunolins16 Feb 3, 2023
b3b7cef
Fixing linker suppressions
brunolins16 Feb 3, 2023
5715427
Simplify and using PostConfigureOptions
brunolins16 Feb 6, 2023
67faf3f
Clean up
brunolins16 Feb 6, 2023
ede0a7e
Fixing unit tests
brunolins16 Feb 7, 2023
a7ae048
Fix unit test
brunolins16 Feb 8, 2023
422cb93
Trying fix SignalR
brunolins16 Feb 8, 2023
8edd3b7
Revert "Trying fix SignalR"
brunolins16 Feb 8, 2023
cde347e
Update Startup.cs
brunolins16 Feb 8, 2023
a18c01b
Changing to a IOptionsFactory
brunolins16 Feb 8, 2023
d45eea5
Move to singleton
brunolins16 Feb 8, 2023
298f9e5
Trying another approach
brunolins16 Feb 10, 2023
fe7434a
Clean up
brunolins16 Feb 10, 2023
580d227
More clean up
brunolins16 Feb 10, 2023
6dfe6c1
More clean up
brunolins16 Feb 10, 2023
e7e44a5
Merge branch 'brunolins16/aot/json/reflection-json-options' of https:…
brunolins16 Feb 10, 2023
afd6762
More clean up
brunolins16 Feb 10, 2023
c251205
Fix mvc
brunolins16 Feb 10, 2023
19c9465
Merge remote-tracking branch 'upstream/main' into brunolins16/aot/jso…
brunolins16 Feb 15, 2023
c01dc5f
More clean up
brunolins16 Feb 15, 2023
473e2eb
Merge remote-tracking branch 'upstream/main' into brunolins16/aot/jso…
brunolins16 Feb 15, 2023
9ceb581
More clean up
brunolins16 Feb 15, 2023
5bfb9e1
Cleaning up JsonHttpResult
brunolins16 Feb 15, 2023
aaed7dc
More clean up
brunolins16 Feb 16, 2023
79d5117
More clean up
brunolins16 Feb 16, 2023
7637bdd
Moving changes to #46716
brunolins16 Feb 16, 2023
14a5aac
Fix comment
brunolins16 Feb 17, 2023
35556da
Removing public api
brunolins16 Feb 24, 2023
08e1545
Merge remote-tracking branch 'upstream/main' into brunolins16/aot/jso…
brunolins16 Feb 24, 2023
29fd8cd
PR feedback updates
brunolins16 Feb 24, 2023
8c830d1
Removing extra usings
brunolins16 Feb 24, 2023
2c5caff
Fix tests
brunolins16 Feb 28, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@

using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;
using Microsoft.AspNetCore.Http.Json;

namespace Microsoft.AspNetCore.Http.Abstractions.Tests;

public class HttpValidationProblemDetailsJsonConverterTest
{
private static JsonSerializerOptions JsonSerializerOptions => new JsonOptions().SerializerOptions;
private static JsonSerializerOptions JsonSerializerOptions => new JsonSerializerOptions(new JsonOptions().SerializerOptions)
{
TypeInfoResolver = new DefaultJsonTypeInfoResolver()
};

[Fact]
public void Write_Works()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization.Metadata;
using Microsoft.AspNetCore.Http.Json;
using Microsoft.AspNetCore.Mvc;

namespace Microsoft.AspNetCore.Http.Abstractions.Tests;

public class ProblemDetailsJsonConverterTest
{
private static JsonSerializerOptions JsonSerializerOptions => new JsonOptions().SerializerOptions;
private static JsonSerializerOptions JsonSerializerOptions => new JsonSerializerOptions(new JsonOptions().SerializerOptions)
{
TypeInfoResolver = new DefaultJsonTypeInfoResolver()
};

[Fact]
public void Read_ThrowsIfJsonIsIncomplete()
Expand Down
4 changes: 2 additions & 2 deletions src/Http/Http.Extensions/src/HttpRequestJsonExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public static class HttpRequestJsonExtensions
ArgumentNullException.ThrowIfNull(request);

var options = ResolveSerializerOptions(request.HttpContext);
return request.ReadFromJsonAsync(jsonTypeInfo: (JsonTypeInfo<TValue>)options.GetTypeInfo(typeof(TValue)), cancellationToken);
return request.ReadFromJsonAsync(jsonTypeInfo: (JsonTypeInfo<TValue>)options.GetReadOnlyTypeInfo(typeof(TValue)), cancellationToken);
}

/// <summary>
Expand Down Expand Up @@ -175,7 +175,7 @@ public static class HttpRequestJsonExtensions
ArgumentNullException.ThrowIfNull(request);

var options = ResolveSerializerOptions(request.HttpContext);
return request.ReadFromJsonAsync(jsonTypeInfo: options.GetTypeInfo(type), cancellationToken);
return request.ReadFromJsonAsync(jsonTypeInfo: options.GetReadOnlyTypeInfo(type), cancellationToken);
}

/// <summary>
Expand Down
4 changes: 2 additions & 2 deletions src/Http/Http.Extensions/src/HttpResponseJsonExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public static Task WriteAsJsonAsync<TValue>(
ArgumentNullException.ThrowIfNull(response);

var options = ResolveSerializerOptions(response.HttpContext);
return response.WriteAsJsonAsync(value, jsonTypeInfo: (JsonTypeInfo<TValue>)options.GetTypeInfo(typeof(TValue)), contentType: null, cancellationToken);
return response.WriteAsJsonAsync(value, jsonTypeInfo: (JsonTypeInfo<TValue>)options.GetReadOnlyTypeInfo(typeof(TValue)), contentType: null, cancellationToken);
}

/// <summary>
Expand Down Expand Up @@ -213,7 +213,7 @@ public static Task WriteAsJsonAsync(
ArgumentNullException.ThrowIfNull(response);

var options = ResolveSerializerOptions(response.HttpContext);
return response.WriteAsJsonAsync(value, jsonTypeInfo: options.GetTypeInfo(type), contentType: null, cancellationToken);
return response.WriteAsJsonAsync(value, jsonTypeInfo: options.GetReadOnlyTypeInfo(type), contentType: null, cancellationToken);
}

/// <summary>
Expand Down
14 changes: 0 additions & 14 deletions src/Http/Http.Extensions/src/JsonOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;
using Microsoft.AspNetCore.Internal;

#nullable enable

Expand All @@ -23,23 +21,11 @@ public class JsonOptions
// Because these options are for producing content that is written directly to the request
// (and not embedded in an HTML page for example), we can use UnsafeRelaxedJsonEscaping.
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,

// The JsonSerializerOptions.GetTypeInfo method is called directly and needs a defined resolver
// setting the default resolver (reflection-based) but the user can overwrite it directly or calling
// .AddContext<TContext>()
TypeInfoResolver = TrimmingAppContextSwitches.EnsureJsonTrimmability ? null : CreateDefaultTypeResolver()
};

// Use a copy so the defaults are not modified.
/// <summary>
/// Gets the <see cref="JsonSerializerOptions"/>.
/// </summary>
public JsonSerializerOptions SerializerOptions { get; internal set; } = new JsonSerializerOptions(DefaultSerializerOptions);

#pragma warning disable IL2026 // Suppressed in Microsoft.AspNetCore.Http.Extensions.WarningSuppressions.xml
#pragma warning disable IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.
private static IJsonTypeInfoResolver CreateDefaultTypeResolver()
=> new DefaultJsonTypeInfoResolver();
#pragma warning restore IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.
#pragma warning restore IL2026 // Suppressed in Microsoft.AspNetCore.Http.Extensions.WarningSuppressions.xml
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
<argument>ILLink</argument>
<argument>IL2026</argument>
<property name="Scope">member</property>
<property name="Target">M:Microsoft.AspNetCore.Http.Json.JsonOptions.CreateDefaultTypeResolver</property>
<property name="Justification">This warning is left in the product so developers get an ILLink warning when trimming an app, in future, only when Microsoft.AspNetCore.EnsureJsonTrimmability=false.</property>
<property name="Target">M:Microsoft.AspNetCore.Http.JsonSerializerExtensions.Configure(System.Text.Json.JsonSerializerOptions)</property>
<property name="Justification">This warning is left in the product so developers get an ILLink warning when trimming an app only when Microsoft.AspNetCore.EnsureJsonTrimmability=false.</property>
</attribute>
</assembly>
</linker>
</linker>
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<Compile Include="$(SharedSourceRoot)Json\JsonSerializerExtensions.cs" LinkBase="Shared" />
<Compile Include="$(SharedSourceRoot)TrimmingAppContextSwitches.cs" LinkBase="Shared" />
<Compile Include="$(SharedSourceRoot)RouteHandlers\ExecuteHandlerHelper.cs" LinkBase="Shared"/>
</ItemGroup>
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="Properties\ILLink.Substitutions.xml" LogicalName="ILLink.Substitutions.xml" />
Expand Down
2 changes: 1 addition & 1 deletion src/Http/Http.Extensions/src/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#nullable enable
static Microsoft.AspNetCore.Http.HttpRequestJsonExtensions.ReadFromJsonAsync(this Microsoft.AspNetCore.Http.HttpRequest! request, System.Text.Json.Serialization.Metadata.JsonTypeInfo! jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask<object?>
static Microsoft.AspNetCore.Http.HttpResponseJsonExtensions.WriteAsJsonAsync(this Microsoft.AspNetCore.Http.HttpResponse! response, object? value, System.Text.Json.Serialization.Metadata.JsonTypeInfo! jsonTypeInfo, string? contentType = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task!
static Microsoft.AspNetCore.Http.HttpResponseJsonExtensions.WriteAsJsonAsync(this Microsoft.AspNetCore.Http.HttpResponse! response, object? value, System.Text.Json.Serialization.Metadata.JsonTypeInfo! jsonTypeInfo, string? contentType = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task!
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;
using Microsoft.Extensions.DependencyInjection;

#nullable enable

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using Microsoft.AspNetCore.Testing;

#nullable enable

Expand Down
47 changes: 0 additions & 47 deletions src/Http/Http.Extensions/test/JsonOptionsTests.cs

This file was deleted.

102 changes: 102 additions & 0 deletions src/Http/Http.Extensions/test/JsonSerializerExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using Microsoft.AspNetCore.Testing;
using Microsoft.DotNet.RemoteExecutor;

namespace Microsoft.AspNetCore.Http.Extensions.Tests;

public partial class JsonSerializerExtensionsTests
{
[ConditionalFact]
[RemoteExecutionSupported]
public void Configure_ThrowsForNullTypeInfoResolver_WhenEnsureJsonTrimmabilityTrue()
{
var options = new RemoteInvokeOptions();
options.RuntimeConfigurationOptions.Add("Microsoft.AspNetCore.EnsureJsonTrimmability", true.ToString());

using var remoteHandle = RemoteExecutor.Invoke(static () =>
{
// Arrange
var options = new JsonSerializerOptions();

// Act & Assert
Assert.Throws<InvalidOperationException>(() => JsonSerializerExtensions.Configure(options));
}, options);
}

[ConditionalFact]
[RemoteExecutionSupported]
public void Configure_Works_WhenEnsureJsonTrimmabilityTrue()
{
var options = new RemoteInvokeOptions();
options.RuntimeConfigurationOptions.Add("Microsoft.AspNetCore.EnsureJsonTrimmability", true.ToString());

using var remoteHandle = RemoteExecutor.Invoke(static () =>
{
// Arrange
var options = new JsonSerializerOptions() { TypeInfoResolver = JsonSerializerExtensionsTestsContext.Default };

// Act
JsonSerializerExtensions.Configure(options);

// Assert
Assert.NotNull(options.TypeInfoResolver);
Assert.IsType<JsonSerializerExtensionsTestsContext>(options.TypeInfoResolver);
Assert.True(options.IsReadOnly);
}, options);
}

[ConditionalFact]
[RemoteExecutionSupported]
public void DefaultSerializerOptions_Works_WhenEnsureJsonTrimmabilityFalse()
{
var options = new RemoteInvokeOptions();
options.RuntimeConfigurationOptions.Add("Microsoft.AspNetCore.EnsureJsonTrimmability", false.ToString());

using var remoteHandle = RemoteExecutor.Invoke(static () =>
{
// Arrange
var options = new JsonSerializerOptions();

// Act
JsonSerializerExtensions.Configure(options);

// Assert
Assert.NotNull(options.TypeInfoResolver);
Assert.IsType<DefaultJsonTypeInfoResolver>(options.TypeInfoResolver);
Assert.True(options.IsReadOnly);
}, options);
}

[ConditionalFact]
[RemoteExecutionSupported]
public void DefaultSerializerOptions_Combines_WhenEnsureJsonTrimmabilityFalse()
{
var options = new RemoteInvokeOptions();
options.RuntimeConfigurationOptions.Add("Microsoft.AspNetCore.EnsureJsonTrimmability", false.ToString());

using var remoteHandle = RemoteExecutor.Invoke(static () =>
{
// Arrange
var options = new JsonSerializerOptions() { TypeInfoResolver = JsonSerializerExtensionsTestsContext.Default };

// Act
JsonSerializerExtensions.Configure(options);

// Assert
Assert.NotNull(options.TypeInfoResolver);
Assert.IsNotType<DefaultJsonTypeInfoResolver>(options.TypeInfoResolver);
Assert.IsNotType<JsonSerializerExtensionsTestsContext>(options.TypeInfoResolver);
Assert.NotNull(options.TypeInfoResolver.GetTypeInfo(typeof(string), options));
Assert.True(options.IsReadOnly);
}, options);
}

[JsonSerializable(typeof(object))]
private partial class JsonSerializerExtensionsTestsContext : JsonSerializerContext
{ }
}
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,12 @@ private static IServiceProvider CreateServices()
private static DefaultProblemDetailsWriter GetWriter(ProblemDetailsOptions options = null, JsonOptions jsonOptions = null)
{
options ??= new ProblemDetailsOptions();
jsonOptions ??= new JsonOptions();

if (jsonOptions is null)
{
jsonOptions = new JsonOptions();
jsonOptions.SerializerOptions.TypeInfoResolver = new DefaultJsonTypeInfoResolver();
}

return new DefaultProblemDetailsWriter(Options.Create(options), Options.Create(jsonOptions));
}
Expand Down
Loading