diff --git a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/JsonContent.cs b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/JsonContent.cs index 3e28569417acc..cdd1472cd4e42 100644 --- a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/JsonContent.cs +++ b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/JsonContent.cs @@ -19,8 +19,7 @@ public sealed partial class JsonContent : HttpContent private static MediaTypeHeaderValue DefaultMediaType => new MediaTypeHeaderValue(JsonMediaType) { CharSet = "utf-8" }; - internal static readonly JsonSerializerOptions s_defaultSerializerOptions - = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; + internal static readonly JsonSerializerOptions s_defaultSerializerOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web); private readonly JsonSerializerOptions? _jsonSerializerOptions; public Type ObjectType { get; } diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpClientJsonExtensionsTests.cs b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpClientJsonExtensionsTests.cs index 7ad9f4cd38995..6b38be23d83a3 100644 --- a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpClientJsonExtensionsTests.cs +++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpClientJsonExtensionsTests.cs @@ -13,10 +13,10 @@ namespace System.Net.Http.Json.Functional.Tests { public class HttpClientJsonExtensionsTests { - [Fact] - public async Task TestGetFromJsonAsync() + [Theory] + [MemberData(nameof(ReadFromJsonTestData))] + public async Task TestGetFromJsonAsync(string json) { - string json = Person.Create().Serialize(); HttpHeaderData header = new HttpHeaderData("Content-Type", "application/json"); List headers = new List { header }; @@ -41,6 +41,13 @@ await HttpMessageHandlerLoopbackServer.CreateClientAndServerAsync( server => server.HandleRequestAsync(content: json, headers: headers)); } + public static IEnumerable ReadFromJsonTestData() + { + Person per = Person.Create(); + yield return new object[] { per.Serialize() }; + yield return new object[] { per.SerializeWithNumbersAsStrings() }; + } + [Fact] public async Task TestGetFromJsonAsyncUnsuccessfulResponseAsync() { @@ -114,7 +121,14 @@ await HttpMessageHandlerLoopbackServer.CreateClientAndServerAsync( async server => { HttpRequestData request = await server.HandleRequestAsync(); ValidateRequest(request); - Person obj = JsonSerializer.Deserialize(request.Body, JsonOptions.DefaultSerializerOptions); + + byte[] json = request.Body; + + Person obj = JsonSerializer.Deserialize(json, JsonOptions.DefaultSerializerOptions); + obj.Validate(); + + // Assert numbers are not written as strings - JsonException would be thrown here if written as strings. + obj = JsonSerializer.Deserialize(json, JsonOptions.DefaultSerializerOptions_StrictNumberHandling); obj.Validate(); }); } diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpContentJsonExtensionsTests.cs b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpContentJsonExtensionsTests.cs index 4afeed9305c98..ebc3dc4dcc071 100644 --- a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpContentJsonExtensionsTests.cs +++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpContentJsonExtensionsTests.cs @@ -22,8 +22,9 @@ public void ThrowOnNull() AssertExtensions.Throws("content", () => content.ReadFromJsonAsync(typeof(Person))); } - [Fact] - public async Task HttpContentGetThenReadFromJsonAsync() + [Theory] + [MemberData(nameof(ReadFromJsonTestData))] + public async Task HttpContentGetThenReadFromJsonAsync(string json) { await HttpMessageHandlerLoopbackServer.CreateClientAndServerAsync( async (handler, uri) => @@ -42,7 +43,14 @@ await HttpMessageHandlerLoopbackServer.CreateClientAndServerAsync( per.Validate(); } }, - server => server.HandleRequestAsync(headers: _headers, content: Person.Create().Serialize())); + server => server.HandleRequestAsync(headers: _headers, content: json)); + } + + public static IEnumerable ReadFromJsonTestData() + { + Person per = Person.Create(); + yield return new object[] { per.Serialize() }; + yield return new object[] { per.SerializeWithNumbersAsStrings() }; } [Fact] diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/TestClasses.cs b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/TestClasses.cs index 2ca9ed419e607..5cf685220049c 100644 --- a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/TestClasses.cs +++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/TestClasses.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.Diagnostics.CodeAnalysis; using System.Text.Json; using System.Text.Json.Serialization; using Xunit; @@ -32,16 +31,23 @@ public string Serialize(JsonSerializerOptions options = null) { return JsonSerializer.Serialize(this, options); } + + public string SerializeWithNumbersAsStrings(JsonSerializerOptions options = null) + { + options ??= new JsonSerializerOptions(); + options.NumberHandling = options.NumberHandling | JsonNumberHandling.WriteAsString; + return JsonSerializer.Serialize(this, options); + } } internal static class JsonOptions { - public static readonly JsonSerializerOptions DefaultSerializerOptions - = new JsonSerializerOptions - { - PropertyNameCaseInsensitive = true, - PropertyNamingPolicy = JsonNamingPolicy.CamelCase - }; + public static readonly JsonSerializerOptions DefaultSerializerOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web); + + public static readonly JsonSerializerOptions DefaultSerializerOptions_StrictNumberHandling = new JsonSerializerOptions(DefaultSerializerOptions) + { + NumberHandling = JsonNumberHandling.Strict + }; } internal class EnsureDefaultOptionsConverter : JsonConverter @@ -68,7 +74,8 @@ public override void Write(Utf8JsonWriter writer, EnsureDefaultOptions value, Js private static void AssertDefaultOptions(JsonSerializerOptions options) { Assert.True(options.PropertyNameCaseInsensitive); - Assert.Equal(JsonNamingPolicy.CamelCase, options.PropertyNamingPolicy); + Assert.Same(JsonNamingPolicy.CamelCase, options.PropertyNamingPolicy); + Assert.Equal(JsonNumberHandling.AllowReadingFromString, options.NumberHandling); } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerDefaults.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerDefaults.cs index fe762976f8a05..6b03ff95d602f 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerDefaults.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerDefaults.cs @@ -19,7 +19,7 @@ public enum JsonSerializerDefaults /// Specifies that values should be used more appropriate to web-based scenarios. /// /// - /// This option implies that property names are treated as case-insensitive and that "camelCase" name formatting should be employed. + /// This option implies that property names are treated as case-insensitive, "camelCase" name formatting should be employed, and that numbers can be read from JSON strings. /// Web = 1 } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs index be273a2483b73..ff146a6273f8a 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs @@ -106,6 +106,7 @@ public JsonSerializerOptions(JsonSerializerDefaults defaults) : this() { _propertyNameCaseInsensitive = true; _jsonPropertyNamingPolicy = JsonNamingPolicy.CamelCase; + _numberHandling = JsonNumberHandling.AllowReadingFromString; } else if (defaults != JsonSerializerDefaults.General) { diff --git a/src/libraries/System.Text.Json/tests/Serialization/OptionsTests.cs b/src/libraries/System.Text.Json/tests/Serialization/OptionsTests.cs index a7cc37fb68f1c..b0fa10a473ce8 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/OptionsTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/OptionsTests.cs @@ -533,9 +533,9 @@ public static void DefaultSerializerOptions_General() public static void PredefinedSerializerOptions_Web() { var options = new JsonSerializerOptions(JsonSerializerDefaults.Web); - JsonNamingPolicy policy = options.PropertyNamingPolicy; Assert.True(options.PropertyNameCaseInsensitive); - Assert.Same(JsonNamingPolicy.CamelCase, policy); + Assert.Same(JsonNamingPolicy.CamelCase, options.PropertyNamingPolicy); + Assert.Equal(JsonNumberHandling.AllowReadingFromString, options.NumberHandling); } [Theory]