From fc095beef9fcc72ce04530740429ceb8b5587d5d Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 6 Feb 2023 16:59:36 -0800 Subject: [PATCH 1/2] Removing custom ProblemDetails Converters --- ...rosoft.AspNetCore.Http.Abstractions.csproj | 2 - .../HttpValidationProblemDetails.cs | 4 +- .../src/ProblemDetails/ProblemDetails.cs | 19 ++- .../src/PublicAPI.Unshipped.txt | 2 + ...lidationProblemDetailsJsonConverterTest.cs | 11 +- .../test/ProblemDetailsJsonConverterTest.cs | 20 +-- .../src/ProblemDetailsJsonContext.cs | 2 - .../src/PublicAPI.Unshipped.txt | 4 +- .../test/ProblemDetailsDefaultWriterTest.cs | 22 +-- .../test/RequestDelegateFactoryTests.cs | 2 +- src/Http/Http.Results/test/JsonResultTests.cs | 14 +- .../Http.Results/test/ProblemResultTests.cs | 11 +- .../test/ValidationProblemResultTests.cs | 2 +- .../ValidationProblemDetailsJsonConverter.cs | 23 --- src/Mvc/Mvc.Core/src/PublicAPI.Unshipped.txt | 4 +- .../Mvc.Core/src/ValidationProblemDetails.cs | 5 +- .../DefaultApiProblemDetailsWriterTest.cs | 2 +- ...lidationProblemDetailsJsonConverterTest.cs | 13 +- ...tpValidationProblemDetailsJsonConverter.cs | 129 ---------------- .../ProblemDetailsJsonConverter.cs | 142 ------------------ 20 files changed, 70 insertions(+), 363 deletions(-) delete mode 100644 src/Mvc/Mvc.Core/src/Infrastructure/ValidationProblemDetailsJsonConverter.cs delete mode 100644 src/Shared/ProblemDetails/HttpValidationProblemDetailsJsonConverter.cs delete mode 100644 src/Shared/ProblemDetails/ProblemDetailsJsonConverter.cs diff --git a/src/Http/Http.Abstractions/src/Microsoft.AspNetCore.Http.Abstractions.csproj b/src/Http/Http.Abstractions/src/Microsoft.AspNetCore.Http.Abstractions.csproj index f03c1052f693..ff0c54dadae1 100644 --- a/src/Http/Http.Abstractions/src/Microsoft.AspNetCore.Http.Abstractions.csproj +++ b/src/Http/Http.Abstractions/src/Microsoft.AspNetCore.Http.Abstractions.csproj @@ -26,8 +26,6 @@ Microsoft.AspNetCore.Http.HttpResponse - - diff --git a/src/Http/Http.Abstractions/src/ProblemDetails/HttpValidationProblemDetails.cs b/src/Http/Http.Abstractions/src/ProblemDetails/HttpValidationProblemDetails.cs index 12ccd028babf..af225a4b13fd 100644 --- a/src/Http/Http.Abstractions/src/ProblemDetails/HttpValidationProblemDetails.cs +++ b/src/Http/Http.Abstractions/src/ProblemDetails/HttpValidationProblemDetails.cs @@ -1,7 +1,6 @@ // 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.Serialization; using Microsoft.AspNetCore.Mvc; namespace Microsoft.AspNetCore.Http; @@ -9,7 +8,6 @@ namespace Microsoft.AspNetCore.Http; /// /// A for validation errors. /// -[JsonConverter(typeof(HttpValidationProblemDetailsJsonConverter))] public class HttpValidationProblemDetails : ProblemDetails { /// @@ -38,5 +36,5 @@ private HttpValidationProblemDetails(Dictionary errors) /// /// Gets the validation errors associated with this instance of . /// - public IDictionary Errors { get; } = new Dictionary(StringComparer.Ordinal); + public IDictionary Errors { get; set; } = new Dictionary(StringComparer.Ordinal); } diff --git a/src/Http/Http.Abstractions/src/ProblemDetails/ProblemDetails.cs b/src/Http/Http.Abstractions/src/ProblemDetails/ProblemDetails.cs index 2d01289cdf19..96c7db573ba0 100644 --- a/src/Http/Http.Abstractions/src/ProblemDetails/ProblemDetails.cs +++ b/src/Http/Http.Abstractions/src/ProblemDetails/ProblemDetails.cs @@ -2,14 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json.Serialization; -using Microsoft.AspNetCore.Http; namespace Microsoft.AspNetCore.Mvc; /// /// A machine-readable format for specifying errors in HTTP API responses based on . /// -[JsonConverter(typeof(ProblemDetailsJsonConverter))] public class ProblemDetails { /// @@ -18,7 +16,8 @@ public class ProblemDetails /// (e.g., using HTML [W3C.REC-html5-20141028]). When this member is not present, its value is assumed to be /// "about:blank". /// - [JsonPropertyName("type")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyOrder(-5)] public string? Type { get; set; } /// @@ -26,25 +25,29 @@ public class ProblemDetails /// of the problem, except for purposes of localization(e.g., using proactive content negotiation; /// see[RFC7231], Section 3.4). /// - [JsonPropertyName("title")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyOrder(-4)] public string? Title { get; set; } /// /// The HTTP status code([RFC7231], Section 6) generated by the origin server for this occurrence of the problem. /// - [JsonPropertyName("status")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyOrder(-3)] public int? Status { get; set; } /// /// A human-readable explanation specific to this occurrence of the problem. /// - [JsonPropertyName("detail")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyOrder(-2)] public string? Detail { get; set; } /// /// A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced. /// - [JsonPropertyName("instance")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyOrder(-1)] public string? Instance { get; set; } /// @@ -59,5 +62,5 @@ public class ProblemDetails /// In particular, complex types or collection types may not round-trip to the original type when using the built-in JSON or XML formatters. /// [JsonExtensionData] - public IDictionary Extensions { get; } = new Dictionary(StringComparer.Ordinal); + public IDictionary Extensions { get; set; } = new Dictionary(StringComparer.Ordinal); } diff --git a/src/Http/Http.Abstractions/src/PublicAPI.Unshipped.txt b/src/Http/Http.Abstractions/src/PublicAPI.Unshipped.txt index 148bf26feed8..02bab97ce6e7 100644 --- a/src/Http/Http.Abstractions/src/PublicAPI.Unshipped.txt +++ b/src/Http/Http.Abstractions/src/PublicAPI.Unshipped.txt @@ -1,4 +1,6 @@ #nullable enable Microsoft.AspNetCore.Http.HttpResults.EmptyHttpResult Microsoft.AspNetCore.Http.HttpResults.EmptyHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpValidationProblemDetails.Errors.set -> void +Microsoft.AspNetCore.Mvc.ProblemDetails.Extensions.set -> void static Microsoft.AspNetCore.Http.HttpResults.EmptyHttpResult.Instance.get -> Microsoft.AspNetCore.Http.HttpResults.EmptyHttpResult! \ No newline at end of file diff --git a/src/Http/Http.Abstractions/test/HttpValidationProblemDetailsJsonConverterTest.cs b/src/Http/Http.Abstractions/test/HttpValidationProblemDetailsJsonConverterTest.cs index 838bcd836243..b2c791d102bd 100644 --- a/src/Http/Http.Abstractions/test/HttpValidationProblemDetailsJsonConverterTest.cs +++ b/src/Http/Http.Abstractions/test/HttpValidationProblemDetailsJsonConverterTest.cs @@ -14,7 +14,6 @@ public class HttpValidationProblemDetailsJsonConverterTest [Fact] public void Write_Works() { - var converter = new HttpValidationProblemDetailsJsonConverter(); var problemDetails = new HttpValidationProblemDetails(); problemDetails.Type = "https://tools.ietf.org/html/rfc9110#section-15.5.5"; @@ -28,7 +27,7 @@ public void Write_Works() var ms = new MemoryStream(); var writer = new Utf8JsonWriter(ms); - converter.Write(writer, problemDetails, JsonSerializerOptions); + JsonSerializer.Serialize(writer, problemDetails, JsonSerializerOptions); writer.Flush(); ms.Seek(0, SeekOrigin.Begin); @@ -57,13 +56,13 @@ public void Read_Works() var traceId = "|37dd3dd5-4a9619f953c40a16."; var json = $"{{\"type\":\"{type}\",\"title\":\"{title}\",\"status\":{status},\"detail\":\"{detail}\", \"instance\":\"{instance}\",\"traceId\":\"{traceId}\"," + "\"errors\":{\"key0\":[\"error0\"],\"key1\":[\"error1\",\"error2\"]}}"; - var converter = new HttpValidationProblemDetailsJsonConverter(); var reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(json)); reader.Read(); // Act - var problemDetails = converter.Read(ref reader, typeof(HttpValidationProblemDetails), JsonSerializerOptions); + var problemDetails = JsonSerializer.Deserialize(ref reader, JsonSerializerOptions); + Assert.NotNull(problemDetails); Assert.Equal(type, problemDetails.Type); Assert.Equal(title, problemDetails.Title); Assert.Equal(status, problemDetails.Status); @@ -100,13 +99,13 @@ public void Read_WithSomeMissingValues_Works() var traceId = "|37dd3dd5-4a9619f953c40a16."; var json = $"{{\"type\":\"{type}\",\"title\":\"{title}\",\"status\":{status},\"traceId\":\"{traceId}\"," + "\"errors\":{\"key0\":[\"error0\"],\"key1\":[\"error1\",\"error2\"]}}"; - var converter = new HttpValidationProblemDetailsJsonConverter(); var reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(json)); reader.Read(); // Act - var problemDetails = converter.Read(ref reader, typeof(HttpValidationProblemDetails), JsonSerializerOptions); + var problemDetails = JsonSerializer.Deserialize(ref reader, JsonSerializerOptions); + Assert.NotNull(problemDetails); Assert.Equal(type, problemDetails.Type); Assert.Equal(title, problemDetails.Title); Assert.Equal(status, problemDetails.Status); diff --git a/src/Http/Http.Abstractions/test/ProblemDetailsJsonConverterTest.cs b/src/Http/Http.Abstractions/test/ProblemDetailsJsonConverterTest.cs index 666303b71df9..4c3c1d8731db 100644 --- a/src/Http/Http.Abstractions/test/ProblemDetailsJsonConverterTest.cs +++ b/src/Http/Http.Abstractions/test/ProblemDetailsJsonConverterTest.cs @@ -18,13 +18,12 @@ public void Read_ThrowsIfJsonIsIncomplete() { // Arrange var json = "{"; - var converter = new ProblemDetailsJsonConverter(); // Act & Assert var ex = Record.Exception(() => { var reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(json)); - converter.Read(ref reader, typeof(ProblemDetails), JsonSerializerOptions); + JsonSerializer.Deserialize(ref reader, typeof(ProblemDetails), JsonSerializerOptions);; }); Assert.IsAssignableFrom(ex); } @@ -40,14 +39,14 @@ public void Read_Works() var instance = "http://example.com/products/14"; var traceId = "|37dd3dd5-4a9619f953c40a16."; var json = $"{{\"type\":\"{type}\",\"title\":\"{title}\",\"status\":{status},\"detail\":\"{detail}\", \"instance\":\"{instance}\",\"traceId\":\"{traceId}\"}}"; - var converter = new ProblemDetailsJsonConverter(); var reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(json)); reader.Read(); // Act - var problemDetails = converter.Read(ref reader, typeof(ProblemDetails), JsonSerializerOptions); + var problemDetails = JsonSerializer.Deserialize(ref reader, JsonSerializerOptions); //Assert + Assert.NotNull(problemDetails); Assert.Equal(type, problemDetails.Type); Assert.Equal(title, problemDetails.Title); Assert.Equal(status, problemDetails.Status); @@ -135,14 +134,14 @@ public void Read_WithSomeMissingValues_Works() var status = 404; var traceId = "|37dd3dd5-4a9619f953c40a16."; var json = $"{{\"type\":\"{type}\",\"title\":\"{title}\",\"status\":{status},\"traceId\":\"{traceId}\"}}"; - var converter = new ProblemDetailsJsonConverter(); var reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(json)); reader.Read(); // Act - var problemDetails = converter.Read(ref reader, typeof(ProblemDetails), JsonSerializerOptions); + var problemDetails = JsonSerializer.Deserialize(ref reader, JsonSerializerOptions); // Assert + Assert.NotNull(problemDetails); Assert.Equal(type, problemDetails.Type); Assert.Equal(title, problemDetails.Title); Assert.Equal(status, problemDetails.Status); @@ -174,13 +173,12 @@ public void Write_Works() } }; var expected = $"{{\"type\":\"{JsonEncodedText.Encode(value.Type)}\",\"title\":\"{value.Title}\",\"status\":{value.Status},\"detail\":\"{value.Detail}\",\"instance\":\"{JsonEncodedText.Encode(value.Instance)}\",\"traceId\":\"{traceId}\",\"some-data\":[\"value1\",\"value2\"]}}"; - var converter = new ProblemDetailsJsonConverter(); var stream = new MemoryStream(); // Act using (var writer = new Utf8JsonWriter(stream)) { - converter.Write(writer, value, JsonSerializerOptions); + JsonSerializer.Serialize(writer, value, JsonSerializerOptions); } // Assert @@ -199,13 +197,12 @@ public void Write_WithSomeMissingContent_Works() Status = 404, }; var expected = $"{{\"type\":\"{JsonEncodedText.Encode(value.Type)}\",\"title\":\"{value.Title}\",\"status\":{value.Status}}}"; - var converter = new ProblemDetailsJsonConverter(); var stream = new MemoryStream(); // Act using (var writer = new Utf8JsonWriter(stream)) { - converter.Write(writer, value, JsonSerializerOptions); + JsonSerializer.Serialize(writer, value, JsonSerializerOptions); } // Assert @@ -231,13 +228,12 @@ public void Write_WithNullExtensionValue_Works() } }; var expected = $"{{\"type\":\"{JsonEncodedText.Encode(value.Type)}\",\"title\":\"{value.Title}\",\"status\":{value.Status},\"detail\":\"{value.Detail}\",\"instance\":\"{JsonEncodedText.Encode(value.Instance)}\",\"traceId\":null,\"some-data\":[\"value1\",\"value2\"]}}"; - var converter = new ProblemDetailsJsonConverter(); var stream = new MemoryStream(); // Act using (var writer = new Utf8JsonWriter(stream)) { - converter.Write(writer, value, JsonSerializerOptions); + JsonSerializer.Serialize(writer, value, JsonSerializerOptions); } // Assert diff --git a/src/Http/Http.Extensions/src/ProblemDetailsJsonContext.cs b/src/Http/Http.Extensions/src/ProblemDetailsJsonContext.cs index 287b7d93d954..b247e359e483 100644 --- a/src/Http/Http.Extensions/src/ProblemDetailsJsonContext.cs +++ b/src/Http/Http.Extensions/src/ProblemDetailsJsonContext.cs @@ -9,8 +9,6 @@ namespace Microsoft.AspNetCore.Http; [JsonSerializable(typeof(ProblemDetails))] [JsonSerializable(typeof(HttpValidationProblemDetails))] -// ExtensionData -[JsonSerializable(typeof(IDictionary))] // Additional values are specified on JsonSerializerContext to support some values for extensions. // For example, the DeveloperExceptionMiddleware serializes its complex type to JsonElement, which problem details then needs to serialize. [JsonSerializable(typeof(JsonElement))] diff --git a/src/Http/Http.Extensions/src/PublicAPI.Unshipped.txt b/src/Http/Http.Extensions/src/PublicAPI.Unshipped.txt index 393817af3895..2f0545145f3d 100644 --- a/src/Http/Http.Extensions/src/PublicAPI.Unshipped.txt +++ b/src/Http/Http.Extensions/src/PublicAPI.Unshipped.txt @@ -1,3 +1,5 @@ #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 -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! \ No newline at end of file +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! +Microsoft.AspNetCore.Mvc.ProblemDetails.Extensions.set -> void (forwarded, contained in Microsoft.AspNetCore.Http.Abstractions) +Microsoft.AspNetCore.Http.HttpValidationProblemDetails.Errors.set -> void (forwarded, contained in Microsoft.AspNetCore.Http.Abstractions) diff --git a/src/Http/Http.Extensions/test/ProblemDetailsDefaultWriterTest.cs b/src/Http/Http.Extensions/test/ProblemDetailsDefaultWriterTest.cs index 43435af6e8c5..6e21d0a21902 100644 --- a/src/Http/Http.Extensions/test/ProblemDetailsDefaultWriterTest.cs +++ b/src/Http/Http.Extensions/test/ProblemDetailsDefaultWriterTest.cs @@ -16,6 +16,8 @@ namespace Microsoft.AspNetCore.Http.Extensions.Tests; public partial class DefaultProblemDetailsWriterTest { + private static readonly JsonSerializerOptions SerializerOptions = JsonOptions.DefaultSerializerOptions; + [Fact] public async Task WriteAsync_Works() { @@ -42,7 +44,7 @@ public async Task WriteAsync_Works() //Assert stream.Position = 0; - var problemDetails = await JsonSerializer.DeserializeAsync(stream); + var problemDetails = await JsonSerializer.DeserializeAsync(stream, SerializerOptions); Assert.NotNull(problemDetails); Assert.Equal(expectedProblem.Status, problemDetails.Status); Assert.Equal(expectedProblem.Type, problemDetails.Type); @@ -80,7 +82,7 @@ public async Task WriteAsync_Works_WithJsonContext() //Assert stream.Position = 0; - var problemDetails = await JsonSerializer.DeserializeAsync(stream); + var problemDetails = await JsonSerializer.DeserializeAsync(stream, SerializerOptions); Assert.NotNull(problemDetails); Assert.Equal(expectedProblem.Status, problemDetails.Status); Assert.Equal(expectedProblem.Type, problemDetails.Type); @@ -118,7 +120,7 @@ public async Task WriteAsync_Works_WithMultipleJsonContext() //Assert stream.Position = 0; - var problemDetails = await JsonSerializer.DeserializeAsync(stream); + var problemDetails = await JsonSerializer.DeserializeAsync(stream, SerializerOptions); Assert.NotNull(problemDetails); Assert.Equal(expectedProblem.Status, problemDetails.Status); Assert.Equal(expectedProblem.Type, problemDetails.Type); @@ -155,7 +157,7 @@ public async Task WriteAsync_Works_WithHttpValidationProblemDetails() //Assert stream.Position = 0; - var problemDetails = await JsonSerializer.DeserializeAsync(stream); + var problemDetails = await JsonSerializer.DeserializeAsync(stream, SerializerOptions); Assert.NotNull(problemDetails); Assert.Equal(expectedProblem.Status, problemDetails.Status); Assert.Equal(expectedProblem.Type, problemDetails.Type); @@ -196,7 +198,7 @@ public async Task WriteAsync_Works_WithHttpValidationProblemDetails_AndJsonConte //Assert stream.Position = 0; - var problemDetails = await JsonSerializer.DeserializeAsync(stream); + var problemDetails = await JsonSerializer.DeserializeAsync(stream, SerializerOptions); Assert.NotNull(problemDetails); Assert.Equal(expectedProblem.Status, problemDetails.Status); Assert.Equal(expectedProblem.Type, problemDetails.Type); @@ -351,7 +353,7 @@ public async Task WriteAsync_AddExtensions() //Assert stream.Position = 0; - var problemDetails = await JsonSerializer.DeserializeAsync(stream); + var problemDetails = await JsonSerializer.DeserializeAsync(stream, SerializerOptions); Assert.NotNull(problemDetails); Assert.Collection(problemDetails.Extensions, (extension) => @@ -392,7 +394,7 @@ public async Task WriteAsync_AddExtensions_WithJsonContext() //Assert stream.Position = 0; - var problemDetails = await JsonSerializer.DeserializeAsync(stream); + var problemDetails = await JsonSerializer.DeserializeAsync(stream, options.SerializerOptions); Assert.NotNull(problemDetails); Assert.Collection(problemDetails.Extensions, @@ -419,7 +421,7 @@ public async Task WriteAsync_Applies_Defaults() //Assert stream.Position = 0; - var problemDetails = await JsonSerializer.DeserializeAsync(stream); + var problemDetails = await JsonSerializer.DeserializeAsync(stream, SerializerOptions); Assert.NotNull(problemDetails); Assert.Equal(StatusCodes.Status500InternalServerError, problemDetails.Status); Assert.Equal("https://tools.ietf.org/html/rfc9110#section-15.6.1", problemDetails.Type); @@ -452,7 +454,7 @@ await writer.WriteAsync(new ProblemDetailsContext() //Assert stream.Position = 0; - var problemDetails = await JsonSerializer.DeserializeAsync(stream); + var problemDetails = await JsonSerializer.DeserializeAsync(stream, SerializerOptions); Assert.NotNull(problemDetails); Assert.Equal(StatusCodes.Status406NotAcceptable, problemDetails.Status); Assert.Equal("https://tools.ietf.org/html/rfc9110#section-15.5.1", problemDetails.Type); @@ -483,7 +485,7 @@ await writer.WriteAsync(new ProblemDetailsContext() //Assert stream.Position = 0; - var problemDetails = await JsonSerializer.DeserializeAsync(stream); + var problemDetails = await JsonSerializer.DeserializeAsync(stream, SerializerOptions); Assert.NotNull(problemDetails); Assert.Equal(statusCode, problemDetails.Status); Assert.Equal(type, problemDetails.Type); diff --git a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs index 00ece3149df0..97c61e7728c0 100644 --- a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs +++ b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs @@ -6019,7 +6019,7 @@ string HelloName(string name) await requestDelegate(httpContext); // Assert - var decodedResponseBody = JsonSerializer.Deserialize(responseBodyStream.ToArray()); + var decodedResponseBody = JsonSerializer.Deserialize(responseBodyStream.ToArray(), JsonOptions.DefaultSerializerOptions); Assert.Equal(400, httpContext.Response.StatusCode); Assert.Equal("New response", decodedResponseBody!.Detail); } diff --git a/src/Http/Http.Results/test/JsonResultTests.cs b/src/Http/Http.Results/test/JsonResultTests.cs index 963e76c1ebd4..6936aa51c3e0 100644 --- a/src/Http/Http.Results/test/JsonResultTests.cs +++ b/src/Http/Http.Results/test/JsonResultTests.cs @@ -3,6 +3,8 @@ using System.Text; using System.Text.Json; +using System.Text.Unicode; +using Microsoft.AspNetCore.Http.Json; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -12,6 +14,8 @@ namespace Microsoft.AspNetCore.Http.HttpResults; public class JsonResultTests { + private static readonly JsonSerializerOptions SerializerOptions = new JsonOptions().SerializerOptions; + [Fact] public async Task JsonResult_ExecuteAsync_WithNullValue_Works() { @@ -113,7 +117,7 @@ public async Task ExecuteAsync_UsesDefaults_ForProblemDetails() // Arrange var details = new ProblemDetails(); - var result = new JsonHttpResult(details, jsonSerializerOptions: null); + var result = new JsonHttpResult(details, jsonSerializerOptions: SerializerOptions); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { @@ -130,7 +134,7 @@ public async Task ExecuteAsync_UsesDefaults_ForProblemDetails() // Assert Assert.Equal(StatusCodes.Status500InternalServerError, httpContext.Response.StatusCode); stream.Position = 0; - var responseDetails = JsonSerializer.Deserialize(stream); + var responseDetails = JsonSerializer.Deserialize(stream, SerializerOptions); Assert.Equal("https://tools.ietf.org/html/rfc9110#section-15.6.1", responseDetails.Type); Assert.Equal("An error occurred while processing your request.", responseDetails.Title); Assert.Equal(StatusCodes.Status500InternalServerError, responseDetails.Status); @@ -142,7 +146,7 @@ public async Task ExecuteAsync_UsesDefaults_ForValidationProblemDetails() // Arrange var details = new HttpValidationProblemDetails(); - var result = new JsonHttpResult(details, jsonSerializerOptions: null); + var result = new JsonHttpResult(details, jsonSerializerOptions: SerializerOptions); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { @@ -159,7 +163,7 @@ public async Task ExecuteAsync_UsesDefaults_ForValidationProblemDetails() // Assert Assert.Equal(StatusCodes.Status400BadRequest, httpContext.Response.StatusCode); stream.Position = 0; - var responseDetails = JsonSerializer.Deserialize(stream); + var responseDetails = JsonSerializer.Deserialize(stream, SerializerOptions); Assert.Equal("https://tools.ietf.org/html/rfc9110#section-15.5.1", responseDetails.Type); Assert.Equal("One or more validation errors occurred.", responseDetails.Title); Assert.Equal(StatusCodes.Status400BadRequest, responseDetails.Status); @@ -191,7 +195,7 @@ public async Task ExecuteAsync_UsesDefaults_HttpStatusCodesWithoutTypes() // Assert Assert.Equal(StatusCodes.Status418ImATeapot, httpContext.Response.StatusCode); stream.Position = 0; - var responseDetails = JsonSerializer.Deserialize(stream); + var responseDetails = JsonSerializer.Deserialize(stream, SerializerOptions); Assert.Null(responseDetails.Type); Assert.Equal("I'm a teapot", responseDetails.Title); Assert.Equal(StatusCodes.Status418ImATeapot, responseDetails.Status); diff --git a/src/Http/Http.Results/test/ProblemResultTests.cs b/src/Http/Http.Results/test/ProblemResultTests.cs index 4862638f27ed..efec43a2e9b4 100644 --- a/src/Http/Http.Results/test/ProblemResultTests.cs +++ b/src/Http/Http.Results/test/ProblemResultTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json; +using Microsoft.AspNetCore.Http.Json; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -11,6 +12,8 @@ namespace Microsoft.AspNetCore.Http.HttpResults; public class ProblemResultTests { + private static readonly JsonSerializerOptions SerializerOptions = new JsonOptions().SerializerOptions; + [Fact] public async Task ExecuteAsync_UsesDefaults_ForProblemDetails() { @@ -34,7 +37,7 @@ public async Task ExecuteAsync_UsesDefaults_ForProblemDetails() // Assert Assert.Equal(StatusCodes.Status500InternalServerError, httpContext.Response.StatusCode); stream.Position = 0; - var responseDetails = JsonSerializer.Deserialize(stream); + var responseDetails = JsonSerializer.Deserialize(stream, SerializerOptions); Assert.Equal("https://tools.ietf.org/html/rfc9110#section-15.6.1", responseDetails.Type); Assert.Equal("An error occurred while processing your request.", responseDetails.Title); Assert.Equal(StatusCodes.Status500InternalServerError, responseDetails.Status); @@ -63,7 +66,7 @@ public async Task ExecuteAsync_UsesDefaults_ForValidationProblemDetails() // Assert Assert.Equal(StatusCodes.Status400BadRequest, httpContext.Response.StatusCode); stream.Position = 0; - var responseDetails = JsonSerializer.Deserialize(stream); + var responseDetails = JsonSerializer.Deserialize(stream, SerializerOptions); Assert.Equal("https://tools.ietf.org/html/rfc9110#section-15.5.1", responseDetails.Type); Assert.Equal("One or more validation errors occurred.", responseDetails.Title); Assert.Equal(StatusCodes.Status400BadRequest, responseDetails.Status); @@ -95,7 +98,7 @@ public async Task ExecuteAsync_SetsTitleFromReasonPhrases_WhenNotInDefaults() // Assert Assert.Equal(StatusCodes.Status418ImATeapot, httpContext.Response.StatusCode); stream.Position = 0; - var responseDetails = JsonSerializer.Deserialize(stream); + var responseDetails = JsonSerializer.Deserialize(stream, SerializerOptions); Assert.Null(responseDetails.Type); Assert.Equal("I'm a teapot", responseDetails.Title); Assert.Equal(StatusCodes.Status418ImATeapot, responseDetails.Status); @@ -127,7 +130,7 @@ public async Task ExecuteAsync_IncludeErrors_ForValidationProblemDetails() // Assert Assert.Equal(StatusCodes.Status400BadRequest, httpContext.Response.StatusCode); stream.Position = 0; - var responseDetails = JsonSerializer.Deserialize(stream); + var responseDetails = JsonSerializer.Deserialize(stream, SerializerOptions); Assert.Equal(StatusCodes.Status400BadRequest, responseDetails.Status); var error = Assert.Single(responseDetails.Errors); Assert.Equal("testError", error.Key); diff --git a/src/Http/Http.Results/test/ValidationProblemResultTests.cs b/src/Http/Http.Results/test/ValidationProblemResultTests.cs index 5353379df467..74926c009136 100644 --- a/src/Http/Http.Results/test/ValidationProblemResultTests.cs +++ b/src/Http/Http.Results/test/ValidationProblemResultTests.cs @@ -39,7 +39,7 @@ public async Task ExecuteAsync_UsesDefaults_ForProblemDetails() Assert.Equal(StatusCodes.Status400BadRequest, httpContext.Response.StatusCode); Assert.Equal(details, result.ProblemDetails); stream.Position = 0; - var responseDetails = JsonSerializer.Deserialize(stream); + var responseDetails = JsonSerializer.Deserialize(stream, new JsonSerializerOptions(JsonSerializerDefaults.Web)); Assert.Equal("https://tools.ietf.org/html/rfc9110#section-15.5.1", responseDetails.Type); Assert.Equal("One or more validation errors occurred.", responseDetails.Title); Assert.Equal(StatusCodes.Status400BadRequest, responseDetails.Status); diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/ValidationProblemDetailsJsonConverter.cs b/src/Mvc/Mvc.Core/src/Infrastructure/ValidationProblemDetailsJsonConverter.cs deleted file mode 100644 index 080ab396031d..000000000000 --- a/src/Mvc/Mvc.Core/src/Infrastructure/ValidationProblemDetailsJsonConverter.cs +++ /dev/null @@ -1,23 +0,0 @@ -// 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 Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Mvc.Infrastructure; - -internal sealed class ValidationProblemDetailsJsonConverter : JsonConverter -{ - public override ValidationProblemDetails Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - var problemDetails = new ValidationProblemDetails(); - HttpValidationProblemDetailsJsonConverter.ReadProblemDetails(ref reader, options, problemDetails); - return problemDetails; - } - - public override void Write(Utf8JsonWriter writer, ValidationProblemDetails value, JsonSerializerOptions options) - { - HttpValidationProblemDetailsJsonConverter.WriteProblemDetails(writer, value, options); - } -} diff --git a/src/Mvc/Mvc.Core/src/PublicAPI.Unshipped.txt b/src/Mvc/Mvc.Core/src/PublicAPI.Unshipped.txt index e7461507c391..d88744294890 100644 --- a/src/Mvc/Mvc.Core/src/PublicAPI.Unshipped.txt +++ b/src/Mvc/Mvc.Core/src/PublicAPI.Unshipped.txt @@ -1,5 +1,6 @@ #nullable enable *REMOVED*static Microsoft.AspNetCore.Routing.ControllerLinkGeneratorExtensions.GetUriByAction(this Microsoft.AspNetCore.Routing.LinkGenerator! generator, string! action, string! controller, object? values, string? scheme, Microsoft.AspNetCore.Http.HostString host, Microsoft.AspNetCore.Http.PathString pathBase = default(Microsoft.AspNetCore.Http.PathString), Microsoft.AspNetCore.Http.FragmentString fragment = default(Microsoft.AspNetCore.Http.FragmentString), Microsoft.AspNetCore.Routing.LinkOptions? options = null) -> string? +Microsoft.AspNetCore.Mvc.ValidationProblemDetails.Errors.set -> void static Microsoft.AspNetCore.Routing.ControllerLinkGeneratorExtensions.GetUriByAction(this Microsoft.AspNetCore.Routing.LinkGenerator! generator, string! action, string! controller, object? values, string! scheme, Microsoft.AspNetCore.Http.HostString host, Microsoft.AspNetCore.Http.PathString pathBase = default(Microsoft.AspNetCore.Http.PathString), Microsoft.AspNetCore.Http.FragmentString fragment = default(Microsoft.AspNetCore.Http.FragmentString), Microsoft.AspNetCore.Routing.LinkOptions? options = null) -> string? Microsoft.AspNetCore.Mvc.CreatedResult.CreatedResult() -> void *REMOVED*Microsoft.AspNetCore.Mvc.CreatedResult.CreatedResult(string! location, object? value) -> void @@ -12,4 +13,5 @@ virtual Microsoft.AspNetCore.Mvc.ControllerBase.Created() -> Microsoft.AspNetCor *REMOVED*virtual Microsoft.AspNetCore.Mvc.ControllerBase.Created(string! uri, object? value) -> Microsoft.AspNetCore.Mvc.CreatedResult! *REMOVED*virtual Microsoft.AspNetCore.Mvc.ControllerBase.Created(System.Uri! uri, object? value) -> Microsoft.AspNetCore.Mvc.CreatedResult! virtual Microsoft.AspNetCore.Mvc.ControllerBase.Created(string? uri, object? value) -> Microsoft.AspNetCore.Mvc.CreatedResult! -virtual Microsoft.AspNetCore.Mvc.ControllerBase.Created(System.Uri? uri, object? value) -> Microsoft.AspNetCore.Mvc.CreatedResult! \ No newline at end of file +virtual Microsoft.AspNetCore.Mvc.ControllerBase.Created(System.Uri? uri, object? value) -> Microsoft.AspNetCore.Mvc.CreatedResult! +Microsoft.AspNetCore.Mvc.ProblemDetails.Extensions.set -> void (forwarded, contained in Microsoft.AspNetCore.Http.Abstractions) diff --git a/src/Mvc/Mvc.Core/src/ValidationProblemDetails.cs b/src/Mvc/Mvc.Core/src/ValidationProblemDetails.cs index 5583f2941ca0..0701521ebb3e 100644 --- a/src/Mvc/Mvc.Core/src/ValidationProblemDetails.cs +++ b/src/Mvc/Mvc.Core/src/ValidationProblemDetails.cs @@ -1,10 +1,8 @@ // 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.Serialization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Core; -using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.ModelBinding; namespace Microsoft.AspNetCore.Mvc; @@ -12,7 +10,6 @@ namespace Microsoft.AspNetCore.Mvc; /// /// A for validation errors. /// -[JsonConverter(typeof(ValidationProblemDetailsJsonConverter))] public class ValidationProblemDetails : HttpValidationProblemDetails { /// @@ -84,5 +81,5 @@ public ValidationProblemDetails(IDictionary errors) /// /// Gets the validation errors associated with this instance of . /// - public new IDictionary Errors => base.Errors; + public new IDictionary Errors { get { return base.Errors; } set { base.Errors = value; } } } diff --git a/src/Mvc/Mvc.Core/test/Infrastructure/DefaultApiProblemDetailsWriterTest.cs b/src/Mvc/Mvc.Core/test/Infrastructure/DefaultApiProblemDetailsWriterTest.cs index 4d18639c4633..d51c7504280d 100644 --- a/src/Mvc/Mvc.Core/test/Infrastructure/DefaultApiProblemDetailsWriterTest.cs +++ b/src/Mvc/Mvc.Core/test/Infrastructure/DefaultApiProblemDetailsWriterTest.cs @@ -42,7 +42,7 @@ public async Task WriteAsync_Works() //Assert stream.Position = 0; - var problemDetails = await JsonSerializer.DeserializeAsync(stream); + var problemDetails = await JsonSerializer.DeserializeAsync(stream, new JsonOptions().JsonSerializerOptions); Assert.NotNull(problemDetails); Assert.Equal(expectedProblem.Status, problemDetails.Status); Assert.Equal(expectedProblem.Type, problemDetails.Type); diff --git a/src/Mvc/Mvc.Core/test/Infrastructure/ValidationProblemDetailsJsonConverterTest.cs b/src/Mvc/Mvc.Core/test/Infrastructure/ValidationProblemDetailsJsonConverterTest.cs index df3ef0d94cd3..1aa8b8e4aec9 100644 --- a/src/Mvc/Mvc.Core/test/Infrastructure/ValidationProblemDetailsJsonConverterTest.cs +++ b/src/Mvc/Mvc.Core/test/Infrastructure/ValidationProblemDetailsJsonConverterTest.cs @@ -3,6 +3,7 @@ using System.Text; using System.Text.Json; +using Microsoft.AspNetCore.Http; namespace Microsoft.AspNetCore.Mvc.Infrastructure; @@ -22,12 +23,11 @@ public void Read_Works() var traceId = "|37dd3dd5-4a9619f953c40a16."; var json = $"{{\"type\":\"{type}\",\"title\":\"{title}\",\"status\":{status},\"detail\":\"{detail}\", \"instance\":\"{instance}\",\"traceId\":\"{traceId}\"," + "\"errors\":{\"key0\":[\"error0\"],\"key1\":[\"error1\",\"error2\"]}}"; - var converter = new ValidationProblemDetailsJsonConverter(); var reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(json)); reader.Read(); // Act - var problemDetails = converter.Read(ref reader, typeof(ValidationProblemDetails), JsonSerializerOptions); + var problemDetails = JsonSerializer.Deserialize(ref reader, JsonSerializerOptions); Assert.Equal(type, problemDetails.Type); Assert.Equal(title, problemDetails.Title); @@ -65,12 +65,11 @@ public void Read_WithSomeMissingValues_Works() var traceId = "|37dd3dd5-4a9619f953c40a16."; var json = $"{{\"type\":\"{type}\",\"title\":\"{title}\",\"status\":{status},\"traceId\":\"{traceId}\"," + "\"errors\":{\"key0\":[\"error0\"],\"key1\":[\"error1\",\"error2\"]}}"; - var converter = new ValidationProblemDetailsJsonConverter(); var reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(json)); reader.Read(); // Act - var problemDetails = converter.Read(ref reader, typeof(ValidationProblemDetails), JsonSerializerOptions); + var problemDetails = JsonSerializer.Deserialize(ref reader, JsonSerializerOptions); Assert.Equal(type, problemDetails.Type); Assert.Equal(title, problemDetails.Title); @@ -143,12 +142,11 @@ public void WriteWorks() Status = 400 }; - var converter = new ValidationProblemDetailsJsonConverter(); using MemoryStream stream = new(); using Utf8JsonWriter writer = new(stream); // Act - converter.Write(writer, problemDetails, new JsonSerializerOptions()); + JsonSerializer.Serialize(writer, problemDetails, JsonSerializerOptions); writer.Flush(); var json = Encoding.UTF8.GetString(stream.ToArray()); @@ -175,14 +173,13 @@ public void WriteUsingJsonSerializerOptionsWorks() }; // Act - var converter = new ValidationProblemDetailsJsonConverter(); using MemoryStream stream = new(); using Utf8JsonWriter writer = new(stream); var options = new JsonOptions().JsonSerializerOptions; options.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase; - converter.Write(writer, problemDetails, options); + JsonSerializer.Serialize(writer, problemDetails, options); writer.Flush(); var json = Encoding.UTF8.GetString(stream.ToArray()); diff --git a/src/Shared/ProblemDetails/HttpValidationProblemDetailsJsonConverter.cs b/src/Shared/ProblemDetails/HttpValidationProblemDetailsJsonConverter.cs deleted file mode 100644 index 6686b2c0d8c1..000000000000 --- a/src/Shared/ProblemDetails/HttpValidationProblemDetailsJsonConverter.cs +++ /dev/null @@ -1,129 +0,0 @@ -// 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; - -namespace Microsoft.AspNetCore.Http; - -internal sealed class HttpValidationProblemDetailsJsonConverter : JsonConverter -{ - private static readonly JsonEncodedText Errors = JsonEncodedText.Encode("errors"); - - public override HttpValidationProblemDetails Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - var problemDetails = new HttpValidationProblemDetails(); - return ReadProblemDetails(ref reader, options, problemDetails); - } - - public static HttpValidationProblemDetails ReadProblemDetails(ref Utf8JsonReader reader, JsonSerializerOptions options, HttpValidationProblemDetails problemDetails) - { - if (reader.TokenType != JsonTokenType.StartObject) - { - throw new JsonException("Unexpected end when reading JSON."); - } - - var objectTypeInfo = options.GetTypeInfo(typeof(object)); - while (reader.Read() && reader.TokenType != JsonTokenType.EndObject) - { - if (reader.ValueTextEquals(Errors.EncodedUtf8Bytes)) - { - ReadErrors(ref reader, problemDetails.Errors); - } - else - { - ProblemDetailsJsonConverter.ReadValue(ref reader, problemDetails, objectTypeInfo); - } - } - - if (reader.TokenType != JsonTokenType.EndObject) - { - throw new JsonException("Unexpected end when reading JSON."); - } - - return problemDetails; - - static void ReadErrors(ref Utf8JsonReader reader, IDictionary errors) - { - if (!reader.Read()) - { - throw new JsonException("Unexpected end when reading JSON."); - } - - switch (reader.TokenType) - { - case JsonTokenType.StartObject: - while (reader.Read() && reader.TokenType != JsonTokenType.EndObject) - { - var name = reader.GetString()!; - - if (!reader.Read()) - { - throw new JsonException("Unexpected end when reading JSON."); - } - - if (reader.TokenType == JsonTokenType.Null) - { - errors[name] = null!; - } - else - { - var values = new List(); - while (reader.Read() && reader.TokenType != JsonTokenType.EndArray) - { - values.Add(reader.GetString()!); - } - errors[name] = values.ToArray(); - } - } - break; - case JsonTokenType.Null: - return; - default: - throw new JsonException($"Unexpected token when reading errors: {reader.TokenType}"); - } - } - } - - public override void Write(Utf8JsonWriter writer, HttpValidationProblemDetails value, JsonSerializerOptions options) - { - WriteProblemDetails(writer, value, options); - } - - public static void WriteProblemDetails(Utf8JsonWriter writer, HttpValidationProblemDetails value, JsonSerializerOptions options) - { - writer.WriteStartObject(); - ProblemDetailsJsonConverter.WriteProblemDetails(writer, value, options); - - writer.WritePropertyName(Errors); - WriteErrors(writer, value, options); - - writer.WriteEndObject(); - - static void WriteErrors(Utf8JsonWriter writer, HttpValidationProblemDetails value, JsonSerializerOptions options) - { - writer.WriteStartObject(); - foreach (var kvp in value.Errors) - { - var name = kvp.Key; - var errors = kvp.Value; - - writer.WritePropertyName(options.DictionaryKeyPolicy?.ConvertName(name) ?? name); - if (errors is null) - { - writer.WriteNullValue(); - } - else - { - writer.WriteStartArray(); - foreach (var error in errors) - { - writer.WriteStringValue(error); - } - writer.WriteEndArray(); - } - } - writer.WriteEndObject(); - } - } -} diff --git a/src/Shared/ProblemDetails/ProblemDetailsJsonConverter.cs b/src/Shared/ProblemDetails/ProblemDetailsJsonConverter.cs deleted file mode 100644 index f72524daad9a..000000000000 --- a/src/Shared/ProblemDetails/ProblemDetailsJsonConverter.cs +++ /dev/null @@ -1,142 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics.CodeAnalysis; -using System.Text.Json; -using System.Text.Json.Serialization; -using System.Text.Json.Serialization.Metadata; -using Microsoft.AspNetCore.Mvc; - -namespace Microsoft.AspNetCore.Http; - -internal sealed class ProblemDetailsJsonConverter : JsonConverter -{ - private static readonly JsonEncodedText Type = JsonEncodedText.Encode("type"); - private static readonly JsonEncodedText Title = JsonEncodedText.Encode("title"); - private static readonly JsonEncodedText Status = JsonEncodedText.Encode("status"); - private static readonly JsonEncodedText Detail = JsonEncodedText.Encode("detail"); - private static readonly JsonEncodedText Instance = JsonEncodedText.Encode("instance"); - - public override ProblemDetails Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - var problemDetails = new ProblemDetails(); - - if (reader.TokenType != JsonTokenType.StartObject) - { - throw new JsonException("Unexpected end when reading JSON."); - } - - var objectTypeInfo = options.GetTypeInfo(typeof(object)); - while (reader.Read() && reader.TokenType != JsonTokenType.EndObject) - { - ReadValue(ref reader, problemDetails, objectTypeInfo); - } - - if (reader.TokenType != JsonTokenType.EndObject) - { - throw new JsonException("Unexpected end when reading JSON."); - } - - return problemDetails; - } - - public override void Write(Utf8JsonWriter writer, ProblemDetails value, JsonSerializerOptions options) - { - writer.WriteStartObject(); - WriteProblemDetails(writer, value, options); - writer.WriteEndObject(); - } - - internal static void ReadValue(ref Utf8JsonReader reader, ProblemDetails value, JsonTypeInfo extensionDataTypeInfo) - { - if (TryReadStringProperty(ref reader, Type, out var propertyValue)) - { - value.Type = propertyValue; - } - else if (TryReadStringProperty(ref reader, Title, out propertyValue)) - { - value.Title = propertyValue; - } - else if (TryReadStringProperty(ref reader, Detail, out propertyValue)) - { - value.Detail = propertyValue; - } - else if (TryReadStringProperty(ref reader, Instance, out propertyValue)) - { - value.Instance = propertyValue; - } - else if (reader.ValueTextEquals(Status.EncodedUtf8Bytes)) - { - reader.Read(); - if (reader.TokenType == JsonTokenType.Null) - { - // Nothing to do here. - } - else - { - value.Status = reader.GetInt32(); - } - } - else - { - var key = reader.GetString()!; - reader.Read(); - value.Extensions[key] = JsonSerializer.Deserialize(ref reader, extensionDataTypeInfo); - } - } - - internal static bool TryReadStringProperty(ref Utf8JsonReader reader, JsonEncodedText propertyName, [NotNullWhen(true)] out string? value) - { - if (!reader.ValueTextEquals(propertyName.EncodedUtf8Bytes)) - { - value = default; - return false; - } - - reader.Read(); - value = reader.GetString()!; - return true; - } - - internal static void WriteProblemDetails(Utf8JsonWriter writer, ProblemDetails value, JsonSerializerOptions options) - { - if (value.Type != null) - { - writer.WriteString(Type, value.Type); - } - - if (value.Title != null) - { - writer.WriteString(Title, value.Title); - } - - if (value.Status != null) - { - writer.WriteNumber(Status, value.Status.Value); - } - - if (value.Detail != null) - { - writer.WriteString(Detail, value.Detail); - } - - if (value.Instance != null) - { - writer.WriteString(Instance, value.Instance); - } - - foreach (var kvp in value.Extensions) - { - writer.WritePropertyName(kvp.Key); - - if (kvp.Value is null) - { - writer.WriteNullValue(); - } - else - { - JsonSerializer.Serialize(writer, kvp.Value, options.GetTypeInfo(kvp.Value.GetType())); - } - } - } -} From af14fc48ace8bfbd5f330caa8fb345189e5ac55a Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 15 Feb 2023 10:05:43 -0800 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Safia Abdalla --- src/Http/Http.Results/test/JsonResultTests.cs | 2 +- src/Http/Http.Results/test/ProblemResultTests.cs | 2 +- .../test/Infrastructure/DefaultApiProblemDetailsWriterTest.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Http/Http.Results/test/JsonResultTests.cs b/src/Http/Http.Results/test/JsonResultTests.cs index 6936aa51c3e0..3112cea8a2fc 100644 --- a/src/Http/Http.Results/test/JsonResultTests.cs +++ b/src/Http/Http.Results/test/JsonResultTests.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; public class JsonResultTests { - private static readonly JsonSerializerOptions SerializerOptions = new JsonOptions().SerializerOptions; + private static readonly JsonSerializerOptions SerializerOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web); [Fact] public async Task JsonResult_ExecuteAsync_WithNullValue_Works() diff --git a/src/Http/Http.Results/test/ProblemResultTests.cs b/src/Http/Http.Results/test/ProblemResultTests.cs index efec43a2e9b4..b3ec095809b7 100644 --- a/src/Http/Http.Results/test/ProblemResultTests.cs +++ b/src/Http/Http.Results/test/ProblemResultTests.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; public class ProblemResultTests { - private static readonly JsonSerializerOptions SerializerOptions = new JsonOptions().SerializerOptions; + private static readonly JsonSerializerOptions SerializerOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web); [Fact] public async Task ExecuteAsync_UsesDefaults_ForProblemDetails() diff --git a/src/Mvc/Mvc.Core/test/Infrastructure/DefaultApiProblemDetailsWriterTest.cs b/src/Mvc/Mvc.Core/test/Infrastructure/DefaultApiProblemDetailsWriterTest.cs index d51c7504280d..648e2fa0d73b 100644 --- a/src/Mvc/Mvc.Core/test/Infrastructure/DefaultApiProblemDetailsWriterTest.cs +++ b/src/Mvc/Mvc.Core/test/Infrastructure/DefaultApiProblemDetailsWriterTest.cs @@ -42,7 +42,7 @@ public async Task WriteAsync_Works() //Assert stream.Position = 0; - var problemDetails = await JsonSerializer.DeserializeAsync(stream, new JsonOptions().JsonSerializerOptions); + var problemDetails = await JsonSerializer.DeserializeAsync(stream, new JsonSerializerOptions(JsonSerializerDefaults.Web)); Assert.NotNull(problemDetails); Assert.Equal(expectedProblem.Status, problemDetails.Status); Assert.Equal(expectedProblem.Type, problemDetails.Type);