Add JsonNumberHandling.AllowReadingFromString as a JsonSerializer web default (#41539)
authorLayomi Akinrinade <laakinri@microsoft.com>
Thu, 3 Sep 2020 21:16:13 +0000 (14:16 -0700)
committerGitHub <noreply@github.com>
Thu, 3 Sep 2020 21:16:13 +0000 (14:16 -0700)
* Add JsonNumberHandling.AllowReadingFromString as a JsonSerializer web default

* Add test assertion for number handling option in S.N.H.Json

* Test number-as-string behavior in System.Net.Http.Json

src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/JsonContent.cs
src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpClientJsonExtensionsTests.cs
src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpContentJsonExtensionsTests.cs
src/libraries/System.Net.Http.Json/tests/FunctionalTests/TestClasses.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs
src/libraries/System.Text.Json/tests/Serialization/OptionsTests.cs

index 3e28569..cdd1472 100644 (file)
@@ -19,8 +19,7 @@ namespace System.Net.Http.Json
         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; }
index 7ad9f4c..6b38be2 100644 (file)
@@ -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<HttpHeaderData> headers = new List<HttpHeaderData> { header };
 
@@ -41,6 +41,13 @@ namespace System.Net.Http.Json.Functional.Tests
                 server => server.HandleRequestAsync(content: json, headers: headers));
         }
 
+        public static IEnumerable<object[]> 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 @@ namespace System.Net.Http.Json.Functional.Tests
                 async server => {
                     HttpRequestData request = await server.HandleRequestAsync();
                     ValidateRequest(request);
-                    Person obj = JsonSerializer.Deserialize<Person>(request.Body, JsonOptions.DefaultSerializerOptions);
+
+                    byte[] json = request.Body;
+
+                    Person obj = JsonSerializer.Deserialize<Person>(json, JsonOptions.DefaultSerializerOptions);
+                    obj.Validate();
+
+                    // Assert numbers are not written as strings - JsonException would be thrown here if written as strings.
+                    obj = JsonSerializer.Deserialize<Person>(json, JsonOptions.DefaultSerializerOptions_StrictNumberHandling);
                     obj.Validate();
                 });
         }
index 4afeed9..ebc3dc4 100644 (file)
@@ -22,8 +22,9 @@ namespace System.Net.Http.Json.Functional.Tests
             AssertExtensions.Throws<ArgumentNullException>("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 @@ namespace System.Net.Http.Json.Functional.Tests
                         per.Validate();
                     }
                 },
-                server => server.HandleRequestAsync(headers: _headers, content: Person.Create().Serialize()));
+                server => server.HandleRequestAsync(headers: _headers, content: json));
+        }
+
+        public static IEnumerable<object[]> ReadFromJsonTestData()
+        {
+            Person per = Person.Create();
+            yield return new object[] { per.Serialize() };
+            yield return new object[] { per.SerializeWithNumbersAsStrings() };
         }
 
         [Fact]
index 2ca9ed4..5cf6852 100644 (file)
@@ -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 @@ namespace System.Net.Http.Json.Functional.Tests
         {
             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<EnsureDefaultOptions>
@@ -68,7 +74,8 @@ namespace System.Net.Http.Json.Functional.Tests
         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);
         }
     }
 
index 7f253e4..873046f 100644 (file)
@@ -106,6 +106,7 @@ namespace System.Text.Json
             {
                 _propertyNameCaseInsensitive = true;
                 _jsonPropertyNamingPolicy = JsonNamingPolicy.CamelCase;
+                _numberHandling = JsonNumberHandling.AllowReadingFromString;
             }
             else if (defaults != JsonSerializerDefaults.General)
             {
index a7cc37f..b0fa10a 100644 (file)
@@ -533,9 +533,9 @@ namespace System.Text.Json.Serialization.Tests
         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]