From d8d2e54506c7b1973156316f1dd82c6226de2c95 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Sat, 16 Apr 2016 18:19:48 -0700 Subject: [PATCH] Remove extra options to manipulate `JsonSerializerSettings` - #4339: remove non-recommended JSON formatter constructors - affects `JsonInputFormatter`, `JsonOutputFormatter`, `JsonPatchInputFormatter` - `JsonOutputFormatter` cleanup also impacts `JsonHelper` - rename and make `SerializerSettingsProvider` class public; use it as appropriate - #4409: make `SerializerSetings` properties get-only and `protected` - affects `JsonInputFormatter`, `JsonOutputFormatter` Recommended patterns: - change `JsonSerializerSettings` values in `MvcJsonOptions` for almost all customizations - find `JsonOutputFormatter` in `MvcOptions.OutputFormatters` when limiting per-result formatters - start with `JsonSerializerSettingsProvider.CreateSerializerSettings()` when customizing a per-result formatter --- .../JsonInputFormatter.cs | 53 ++------ .../JsonOutputFormatter.cs | 50 ++------ .../JsonPatchInputFormatter.cs | 22 ++-- ...r.cs => JsonSerializerSettingsProvider.cs} | 4 +- .../MvcJsonOptions.cs | 5 +- .../ViewFeatures/JsonHelper.cs | 15 ++- .../CreatedAtActionResultTests.cs | 6 +- .../CreatedAtRouteResultTests.cs | 6 +- .../CreatedResultTests.cs | 6 +- .../Formatters/FormatFilterTest.cs | 6 +- .../HttpNotFoundObjectResultTest.cs | 6 +- .../HttpOkObjectResultTest.cs | 6 +- .../JsonInputFormatterTest.cs | 103 ++++++--------- .../JsonOutputFormatterTests.cs | 121 ++++-------------- .../JsonPatchInputFormatterTest.cs | 22 +++- .../BasicTests.cs | 13 +- .../TestMvcOptions.cs | 4 +- .../RazorPageActivatorTest.cs | 32 +++-- .../RazorPageCreateTagHelperTest.cs | 8 +- .../MvcOptionsSetupTest.cs | 27 ---- .../BadRequestErrorMessageResultTest.cs | 6 +- .../ExceptionResultTest.cs | 6 +- .../InvalidModelStateResultTest.cs | 6 +- .../NegotiatedContentResultTest.cs | 6 +- test/WebSites/ApiExplorerWebSite/Startup.cs | 5 +- .../FallbackOnTypeBasedMatchController.cs | 20 ++- .../ContentNegotiation/NormalController.cs | 20 ++- .../Controllers/JsonResultController.cs | 18 ++- .../Home/JsonHelperWithSettingsInView.cshtml | 9 +- .../Controllers/ResourceFilterController.cs | 17 +-- .../Controllers/JsonFormatterController.cs | 20 ++- .../ActionResults/ActionResultController.cs | 16 ++- 32 files changed, 304 insertions(+), 360 deletions(-) rename src/Microsoft.AspNetCore.Mvc.Formatters.Json/{Internal/SerializerSettingsProvider.cs => JsonSerializerSettingsProvider.cs} (91%) diff --git a/src/Microsoft.AspNetCore.Mvc.Formatters.Json/JsonInputFormatter.cs b/src/Microsoft.AspNetCore.Mvc.Formatters.Json/JsonInputFormatter.cs index 502cab2d4e..aed8f35194 100644 --- a/src/Microsoft.AspNetCore.Mvc.Formatters.Json/JsonInputFormatter.cs +++ b/src/Microsoft.AspNetCore.Mvc.Formatters.Json/JsonInputFormatter.cs @@ -14,7 +14,7 @@ using Newtonsoft.Json; namespace Microsoft.AspNetCore.Mvc.Formatters { /// - /// An for JSON content. + /// A for JSON content. /// public class JsonInputFormatter : TextInputFormatter { @@ -22,36 +22,16 @@ namespace Microsoft.AspNetCore.Mvc.Formatters private readonly ILogger _logger; private readonly ObjectPoolProvider _objectPoolProvider; private ObjectPool _jsonSerializerPool; - private JsonSerializerSettings _serializerSettings; /// /// Initializes a new instance of . /// /// The . - public JsonInputFormatter(ILogger logger) - : this(logger, SerializerSettingsProvider.CreateSerializerSettings()) - { - } - - /// - /// Initializes a new instance of . - /// - /// The . - /// The . - public JsonInputFormatter(ILogger logger, JsonSerializerSettings serializerSettings) - : this( - logger, - serializerSettings, - ArrayPool.Shared, - new DefaultObjectPoolProvider()) - { - } - - /// - /// Initializes a new instance of . - /// - /// The . - /// The . + /// + /// The . Should be either the application-wide settings + /// () or an instance + /// initially returned. + /// /// The . /// The . public JsonInputFormatter( @@ -81,7 +61,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters } _logger = logger; - _serializerSettings = serializerSettings; + SerializerSettings = serializerSettings; _charPool = new JsonArrayPool(charPool); _objectPoolProvider = objectPoolProvider; @@ -93,28 +73,13 @@ namespace Microsoft.AspNetCore.Mvc.Formatters } /// - /// Gets or sets the used to configure the . + /// Gets the used to configure the . /// /// /// Any modifications to the object after this /// has been used will have no effect. /// - public JsonSerializerSettings SerializerSettings - { - get - { - return _serializerSettings; - } - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - _serializerSettings = value; - } - } + protected JsonSerializerSettings SerializerSettings { get; } /// public override Task ReadRequestBodyAsync( diff --git a/src/Microsoft.AspNetCore.Mvc.Formatters.Json/JsonOutputFormatter.cs b/src/Microsoft.AspNetCore.Mvc.Formatters.Json/JsonOutputFormatter.cs index b235a47120..111a7df47f 100644 --- a/src/Microsoft.AspNetCore.Mvc.Formatters.Json/JsonOutputFormatter.cs +++ b/src/Microsoft.AspNetCore.Mvc.Formatters.Json/JsonOutputFormatter.cs @@ -7,34 +7,30 @@ using System.IO; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Formatters.Json.Internal; -using Microsoft.AspNetCore.Mvc.Internal; using Newtonsoft.Json; namespace Microsoft.AspNetCore.Mvc.Formatters { /// - /// An output formatter that specializes in writing JSON content. + /// A for JSON content. /// public class JsonOutputFormatter : TextOutputFormatter { private readonly IArrayPool _charPool; - private JsonSerializerSettings _serializerSettings; - // Perf: JsonSerializers are relatively expensive to create, and are thread safe. We cache // the serializer and invalidate it when the settings change. private JsonSerializer _serializer; - public JsonOutputFormatter() - : this(SerializerSettingsProvider.CreateSerializerSettings(), ArrayPool.Shared) - { - } - - public JsonOutputFormatter(JsonSerializerSettings serializerSettings) - : this(serializerSettings, ArrayPool.Shared) - { - } - + /// + /// Initializes a new instance. + /// + /// + /// The . Should be either the application-wide settings + /// () or an instance + /// initially returned. + /// + /// The . public JsonOutputFormatter(JsonSerializerSettings serializerSettings, ArrayPool charPool) { if (serializerSettings == null) @@ -47,7 +43,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters throw new ArgumentNullException(nameof(charPool)); } - _serializerSettings = serializerSettings; + SerializerSettings = serializerSettings; _charPool = new JsonArrayPool(charPool); SupportedEncodings.Add(Encoding.UTF8); @@ -57,31 +53,13 @@ namespace Microsoft.AspNetCore.Mvc.Formatters } /// - /// Gets or sets the used to configure the . + /// Gets the used to configure the . /// /// /// Any modifications to the object after this /// has been used will have no effect. /// - public JsonSerializerSettings SerializerSettings - { - get - { - return _serializerSettings; - } - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - _serializerSettings = value; - - // If the settings change, then invalidate the cached serializer. - _serializer = null; - } - } + protected JsonSerializerSettings SerializerSettings { get; } /// /// Writes the given as JSON using the given @@ -157,7 +135,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters WriteObject(writer, context.Object); // Perf: call FlushAsync to call WriteAsync on the stream with any content left in the TextWriter's - // buffers. This is better than just letting dispose handle it (which would result in a synchronous + // buffers. This is better than just letting dispose handle it (which would result in a synchronous // write). await writer.FlushAsync(); } diff --git a/src/Microsoft.AspNetCore.Mvc.Formatters.Json/JsonPatchInputFormatter.cs b/src/Microsoft.AspNetCore.Mvc.Formatters.Json/JsonPatchInputFormatter.cs index dde4b56291..e037e0d4ab 100644 --- a/src/Microsoft.AspNetCore.Mvc.Formatters.Json/JsonPatchInputFormatter.cs +++ b/src/Microsoft.AspNetCore.Mvc.Formatters.Json/JsonPatchInputFormatter.cs @@ -14,17 +14,21 @@ using Newtonsoft.Json; namespace Microsoft.AspNetCore.Mvc.Formatters { + /// + /// A for JSON Patch (application/json-patch+json) content. + /// public class JsonPatchInputFormatter : JsonInputFormatter { - public JsonPatchInputFormatter(ILogger logger) - : this( - logger, - SerializerSettingsProvider.CreateSerializerSettings(), - ArrayPool.Shared, - new DefaultObjectPoolProvider()) - { - } - + /// + /// Initializes a new instance. + /// + /// The . + /// + /// The . Should be either the application-wide settings + /// () or an instance + /// initially returned. + /// /// The . + /// The . public JsonPatchInputFormatter( ILogger logger, JsonSerializerSettings serializerSettings, diff --git a/src/Microsoft.AspNetCore.Mvc.Formatters.Json/Internal/SerializerSettingsProvider.cs b/src/Microsoft.AspNetCore.Mvc.Formatters.Json/JsonSerializerSettingsProvider.cs similarity index 91% rename from src/Microsoft.AspNetCore.Mvc.Formatters.Json/Internal/SerializerSettingsProvider.cs rename to src/Microsoft.AspNetCore.Mvc.Formatters.Json/JsonSerializerSettingsProvider.cs index b80fcb137f..cf26ca32d4 100644 --- a/src/Microsoft.AspNetCore.Mvc.Formatters.Json/Internal/SerializerSettingsProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Formatters.Json/JsonSerializerSettingsProvider.cs @@ -3,12 +3,12 @@ using Newtonsoft.Json; -namespace Microsoft.AspNetCore.Mvc.Formatters.Json.Internal +namespace Microsoft.AspNetCore.Mvc.Formatters { /// /// Helper class which provides . /// - public static class SerializerSettingsProvider + public static class JsonSerializerSettingsProvider { private const int DefaultMaxDepth = 32; diff --git a/src/Microsoft.AspNetCore.Mvc.Formatters.Json/MvcJsonOptions.cs b/src/Microsoft.AspNetCore.Mvc.Formatters.Json/MvcJsonOptions.cs index b273c96fad..3e674a58c9 100644 --- a/src/Microsoft.AspNetCore.Mvc.Formatters.Json/MvcJsonOptions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Formatters.Json/MvcJsonOptions.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNetCore.Mvc.Formatters.Json.Internal; +using Microsoft.AspNetCore.Mvc.Formatters; using Newtonsoft.Json; namespace Microsoft.AspNetCore.Mvc @@ -14,6 +14,7 @@ namespace Microsoft.AspNetCore.Mvc /// /// Gets the that are used by this application. /// - public JsonSerializerSettings SerializerSettings { get; } = SerializerSettingsProvider.CreateSerializerSettings(); + public JsonSerializerSettings SerializerSettings { get; } = + JsonSerializerSettingsProvider.CreateSerializerSettings(); } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewFeatures/JsonHelper.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewFeatures/JsonHelper.cs index 5c43cb92ef..4fcdfc3579 100644 --- a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewFeatures/JsonHelper.cs +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewFeatures/JsonHelper.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.Globalization; using System.IO; using Microsoft.AspNetCore.Html; @@ -17,19 +18,29 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures public class JsonHelper : IJsonHelper { private readonly JsonOutputFormatter _jsonOutputFormatter; + private readonly ArrayPool _charPool; /// /// Initializes a new instance of that is backed by . /// /// The used to serialize JSON. - public JsonHelper(JsonOutputFormatter jsonOutputFormatter) + /// + /// The for use with custom (see + /// ). + /// + public JsonHelper(JsonOutputFormatter jsonOutputFormatter, ArrayPool charPool) { if (jsonOutputFormatter == null) { throw new ArgumentNullException(nameof(jsonOutputFormatter)); } + if (charPool == null) + { + throw new ArgumentNullException(nameof(charPool)); + } _jsonOutputFormatter = jsonOutputFormatter; + _charPool = charPool; } /// @@ -46,7 +57,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures throw new ArgumentNullException(nameof(serializerSettings)); } - var jsonOutputFormatter = new JsonOutputFormatter(serializerSettings); + var jsonOutputFormatter = new JsonOutputFormatter(serializerSettings, _charPool); return SerializeInternal(jsonOutputFormatter, value); } diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/CreatedAtActionResultTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/CreatedAtActionResultTests.cs index ed4237b7fa..7ad73d8b38 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/CreatedAtActionResultTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/CreatedAtActionResultTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; @@ -14,6 +15,7 @@ using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging.Testing; using Moq; +using Newtonsoft.Json; using Xunit; namespace Microsoft.AspNetCore.Mvc @@ -88,7 +90,9 @@ namespace Microsoft.AspNetCore.Mvc { var options = new TestOptionsManager(); options.Value.OutputFormatters.Add(new StringOutputFormatter()); - options.Value.OutputFormatters.Add(new JsonOutputFormatter()); + options.Value.OutputFormatters.Add(new JsonOutputFormatter( + new JsonSerializerSettings(), + ArrayPool.Shared)); var services = new ServiceCollection(); services.AddSingleton(new ObjectResultExecutor( diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/CreatedAtRouteResultTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/CreatedAtRouteResultTests.cs index c4eb5bfbf1..10bc221fe8 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/CreatedAtRouteResultTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/CreatedAtRouteResultTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; @@ -14,6 +15,7 @@ using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging.Testing; using Moq; +using Newtonsoft.Json; using Xunit; namespace Microsoft.AspNetCore.Mvc @@ -103,7 +105,9 @@ namespace Microsoft.AspNetCore.Mvc { var options = new TestOptionsManager(); options.Value.OutputFormatters.Add(new StringOutputFormatter()); - options.Value.OutputFormatters.Add(new JsonOutputFormatter()); + options.Value.OutputFormatters.Add(new JsonOutputFormatter( + new JsonSerializerSettings(), + ArrayPool.Shared)); var services = new ServiceCollection(); services.AddSingleton(new ObjectResultExecutor( diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/CreatedResultTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/CreatedResultTests.cs index 72530581af..8752e1774b 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/CreatedResultTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/CreatedResultTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; @@ -12,6 +13,7 @@ using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging.Testing; using Moq; +using Newtonsoft.Json; using Xunit; namespace Microsoft.AspNetCore.Mvc @@ -89,7 +91,9 @@ namespace Microsoft.AspNetCore.Mvc { var options = new TestOptionsManager(); options.Value.OutputFormatters.Add(new StringOutputFormatter()); - options.Value.OutputFormatters.Add(new JsonOutputFormatter()); + options.Value.OutputFormatters.Add(new JsonOutputFormatter( + new JsonSerializerSettings(), + ArrayPool.Shared)); var services = new ServiceCollection(); services.AddSingleton(new ObjectResultExecutor( diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/FormatFilterTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/FormatFilterTest.cs index 01a659f326..43073d3b48 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/FormatFilterTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/FormatFilterTest.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Buffers; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Filters; @@ -10,6 +11,7 @@ using Microsoft.Extensions.Options; using Microsoft.Extensions.Primitives; using Microsoft.Net.Http.Headers; using Moq; +using Newtonsoft.Json; using Xunit; namespace Microsoft.AspNetCore.Mvc.Formatters @@ -442,7 +444,9 @@ namespace Microsoft.AspNetCore.Mvc.Formatters // Set up default output formatters. Options.OutputFormatters.Add(new HttpNoContentOutputFormatter()); Options.OutputFormatters.Add(new StringOutputFormatter()); - Options.OutputFormatters.Add(new JsonOutputFormatter()); + Options.OutputFormatters.Add(new JsonOutputFormatter( + new JsonSerializerSettings(), + ArrayPool.Shared)); // Set up default mapping for json extensions to content type Options.FormatterMappings.SetMediaTypeMappingForFormat( diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/HttpNotFoundObjectResultTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/HttpNotFoundObjectResultTest.cs index 0bc9a49d7c..9781d5e771 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/HttpNotFoundObjectResultTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/HttpNotFoundObjectResultTest.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; @@ -9,6 +10,7 @@ using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.AspNetCore.Mvc.Internal; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging.Testing; +using Newtonsoft.Json; using Xunit; namespace Microsoft.AspNetCore.Mvc @@ -68,7 +70,9 @@ namespace Microsoft.AspNetCore.Mvc { var options = new TestOptionsManager(); options.Value.OutputFormatters.Add(new StringOutputFormatter()); - options.Value.OutputFormatters.Add(new JsonOutputFormatter()); + options.Value.OutputFormatters.Add(new JsonOutputFormatter( + new JsonSerializerSettings(), + ArrayPool.Shared)); var services = new ServiceCollection(); services.AddSingleton(new ObjectResultExecutor( diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/HttpOkObjectResultTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/HttpOkObjectResultTest.cs index ea08a438cd..48450eb14e 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/HttpOkObjectResultTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/HttpOkObjectResultTest.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Abstractions; @@ -10,6 +11,7 @@ using Microsoft.AspNetCore.Mvc.Internal; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging.Testing; +using Newtonsoft.Json; using Xunit; namespace Microsoft.AspNetCore.Mvc @@ -69,7 +71,9 @@ namespace Microsoft.AspNetCore.Mvc { var options = new TestOptionsManager(); options.Value.OutputFormatters.Add(new StringOutputFormatter()); - options.Value.OutputFormatters.Add(new JsonOutputFormatter()); + options.Value.OutputFormatters.Add(new JsonOutputFormatter( + new JsonSerializerSettings(), + ArrayPool.Shared)); var services = new ServiceCollection(); services.AddSingleton(new ObjectResultExecutor( diff --git a/test/Microsoft.AspNetCore.Mvc.Formatters.Json.Test/JsonInputFormatterTest.cs b/test/Microsoft.AspNetCore.Mvc.Formatters.Json.Test/JsonInputFormatterTest.cs index b32c1d91a1..38d6b8a77e 100644 --- a/test/Microsoft.AspNetCore.Mvc.Formatters.Json.Test/JsonInputFormatterTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Formatters.Json.Test/JsonInputFormatterTest.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.Collections.Generic; using System.IO; using System.Linq; @@ -11,6 +12,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Testing; +using Microsoft.Extensions.ObjectPool; using Moq; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; @@ -20,6 +22,9 @@ namespace Microsoft.AspNetCore.Mvc.Formatters { public class JsonInputFormatterTest { + private static readonly ObjectPoolProvider _objectPoolProvider = new DefaultObjectPoolProvider(); + private static readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings(); + [Theory] [InlineData("application/json", true)] [InlineData("application/*", false)] @@ -36,7 +41,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters // Arrange var loggerMock = GetLogger(); - var formatter = new JsonInputFormatter(loggerMock); + var formatter = + new JsonInputFormatter(loggerMock, _serializerSettings, ArrayPool.Shared, _objectPoolProvider); var contentBytes = Encoding.UTF8.GetBytes("content"); var httpContext = GetHttpContext(contentBytes, contentType: requestContentType); @@ -61,7 +67,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters { // Arrange var loggerMock = GetLogger(); - var formatter = new JsonInputFormatter(loggerMock); + var formatter = + new JsonInputFormatter(loggerMock, _serializerSettings, ArrayPool.Shared, _objectPoolProvider); // Act var mediaType = formatter.SupportedMediaTypes[0]; @@ -87,7 +94,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters { // Arrange var logger = GetLogger(); - var formatter = new JsonInputFormatter(logger); + var formatter = + new JsonInputFormatter(logger, _serializerSettings, ArrayPool.Shared, _objectPoolProvider); var contentBytes = Encoding.UTF8.GetBytes(content); var httpContext = GetHttpContext(contentBytes); @@ -114,7 +122,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters // Arrange var content = "{name: 'Person Name', Age: '30'}"; var logger = GetLogger(); - var formatter = new JsonInputFormatter(logger); + var formatter = + new JsonInputFormatter(logger, _serializerSettings, ArrayPool.Shared, _objectPoolProvider); var contentBytes = Encoding.UTF8.GetBytes(content); var httpContext = GetHttpContext(contentBytes); @@ -143,7 +152,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters // Arrange var content = "[0, 23, 300]"; var logger = GetLogger(); - var formatter = new JsonInputFormatter(logger); + var formatter = + new JsonInputFormatter(logger, _serializerSettings, ArrayPool.Shared, _objectPoolProvider); var contentBytes = Encoding.UTF8.GetBytes(content); var modelState = new ModelStateDictionary(); @@ -176,7 +186,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters // Arrange var content = "[0, 23, 300]"; var logger = GetLogger(); - var formatter = new JsonInputFormatter(logger); + var formatter = + new JsonInputFormatter(logger, _serializerSettings, ArrayPool.Shared, _objectPoolProvider); var contentBytes = Encoding.UTF8.GetBytes(content); var modelState = new ModelStateDictionary(); @@ -205,7 +216,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters // Arrange var content = "{name: 'Person Name', Age: 'not-an-age'}"; var logger = GetLogger(); - var formatter = new JsonInputFormatter(logger); + var formatter = + new JsonInputFormatter(logger, _serializerSettings, ArrayPool.Shared, _objectPoolProvider); var contentBytes = Encoding.UTF8.GetBytes(content); var modelState = new ModelStateDictionary(); @@ -235,7 +247,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters // Arrange var content = "[0, 23, 300]"; var logger = GetLogger(); - var formatter = new JsonInputFormatter(logger); + var formatter = + new JsonInputFormatter(logger, _serializerSettings, ArrayPool.Shared, _objectPoolProvider); var contentBytes = Encoding.UTF8.GetBytes(content); var modelState = new ModelStateDictionary(); @@ -264,7 +277,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters // Arrange var content = "[{name: 'Name One', Age: 30}, {name: 'Name Two', Small: 300}]"; var logger = GetLogger(); - var formatter = new JsonInputFormatter(logger); + var formatter = + new JsonInputFormatter(logger, _serializerSettings, ArrayPool.Shared, _objectPoolProvider); var contentBytes = Encoding.UTF8.GetBytes(content); var modelState = new ModelStateDictionary(); @@ -294,7 +308,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters // Arrange var content = "{name: 'Person Name', Age: 'not-an-age'}"; var logger = GetLogger(); - var formatter = new JsonInputFormatter(logger); + var formatter = + new JsonInputFormatter(logger, _serializerSettings, ArrayPool.Shared, _objectPoolProvider); var contentBytes = Encoding.UTF8.GetBytes(content); var modelState = new ModelStateDictionary(); @@ -322,66 +337,19 @@ namespace Microsoft.AspNetCore.Mvc.Formatters Assert.IsType(error.Exception); } - [Fact] - public void Creates_SerializerSettings_ByDefault() - { - // Arrange - var logger = GetLogger(); - - // Act - var jsonFormatter = new JsonInputFormatter(logger); - - // Assert - Assert.NotNull(jsonFormatter.SerializerSettings); - } - [Fact] public void Constructor_UsesSerializerSettings() { // Arrange - var logger = GetLogger(); + var serializerSettings = new JsonSerializerSettings(); // Act - var serializerSettings = new JsonSerializerSettings(); - var jsonFormatter = new JsonInputFormatter(logger, serializerSettings); + var jsonFormatter = new TestableJsonInputFormatter(serializerSettings); // Assert Assert.Same(serializerSettings, jsonFormatter.SerializerSettings); } - [Fact] - public async Task ChangesTo_DefaultSerializerSettings_TakesEffect() - { - // Arrange - // missing password property here - var contentBytes = Encoding.UTF8.GetBytes("{ \"UserName\" : \"John\"}"); - var logger = GetLogger(); - var jsonFormatter = new JsonInputFormatter(logger); - // by default we ignore missing members, so here explicitly changing it - jsonFormatter.SerializerSettings.MissingMemberHandling = MissingMemberHandling.Error; - - var modelState = new ModelStateDictionary(); - var httpContext = GetHttpContext(contentBytes, "application/json;charset=utf-8"); - var provider = new EmptyModelMetadataProvider(); - var metadata = provider.GetMetadataForType(typeof(UserLogin)); - var inputFormatterContext = new InputFormatterContext( - httpContext, - modelName: string.Empty, - modelState: modelState, - metadata: metadata, - readerFactory: new TestHttpRequestStreamReaderFactory().CreateReader); - - // Act - var result = await jsonFormatter.ReadAsync(inputFormatterContext); - - // Assert - Assert.True(result.HasError); - Assert.False(modelState.IsValid); - - var modelErrorMessage = modelState.Values.First().Errors[0].Exception.Message; - Assert.Contains("Required property 'Password' not found in JSON", modelErrorMessage); - } - [Fact] public async Task CustomSerializerSettingsObject_TakesEffect() { @@ -389,12 +357,11 @@ namespace Microsoft.AspNetCore.Mvc.Formatters // missing password property here var contentBytes = Encoding.UTF8.GetBytes("{ \"UserName\" : \"John\"}"); var logger = GetLogger(); - var jsonFormatter = new JsonInputFormatter(logger); + // by default we ignore missing members, so here explicitly changing it - jsonFormatter.SerializerSettings = new JsonSerializerSettings() - { - MissingMemberHandling = MissingMemberHandling.Error - }; + var serializerSettings = new JsonSerializerSettings { MissingMemberHandling = MissingMemberHandling.Error }; + var jsonFormatter = + new JsonInputFormatter(logger, serializerSettings, ArrayPool.Shared, _objectPoolProvider); var modelState = new ModelStateDictionary(); var httpContext = GetHttpContext(contentBytes, "application/json;charset=utf-8"); @@ -428,7 +395,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters MaxDepth = 2, DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind, }; - var formatter = new TestableJsonInputFormatter(GetLogger(), settings); + var formatter = new TestableJsonInputFormatter(settings); // Act var actual = formatter.CreateJsonSerializer(); @@ -441,11 +408,13 @@ namespace Microsoft.AspNetCore.Mvc.Formatters private class TestableJsonInputFormatter : JsonInputFormatter { - public TestableJsonInputFormatter(ILogger logger, JsonSerializerSettings settings) - : base(logger, settings) + public TestableJsonInputFormatter(JsonSerializerSettings settings) + : base(GetLogger(), settings, ArrayPool.Shared, _objectPoolProvider) { } + public new JsonSerializerSettings SerializerSettings => base.SerializerSettings; + public new JsonSerializer CreateJsonSerializer() => base.CreateJsonSerializer(); } diff --git a/test/Microsoft.AspNetCore.Mvc.Formatters.Json.Test/JsonOutputFormatterTests.cs b/test/Microsoft.AspNetCore.Mvc.Formatters.Json.Test/JsonOutputFormatterTests.cs index 351b0fcdaa..92ce793e6d 100644 --- a/test/Microsoft.AspNetCore.Mvc.Formatters.Json.Test/JsonOutputFormatterTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.Formatters.Json.Test/JsonOutputFormatterTests.cs @@ -2,13 +2,13 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Abstractions; -using Microsoft.AspNetCore.Mvc.Formatters.Json.Internal; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.Logging; @@ -28,9 +28,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters [Fact] public void Creates_SerializerSettings_ByDefault() { - // Arrange - // Act - var jsonFormatter = new JsonOutputFormatter(); + // Arrange & Act + var jsonFormatter = new TestableJsonOutputFormatter(new JsonSerializerSettings()); // Assert Assert.NotNull(jsonFormatter.SerializerSettings); @@ -42,28 +41,26 @@ namespace Microsoft.AspNetCore.Mvc.Formatters // Arrange // Act var serializerSettings = new JsonSerializerSettings(); - var logger = GetLogger(); - var jsonFormatter = new JsonInputFormatter(logger, serializerSettings); + var jsonFormatter = new TestableJsonOutputFormatter(serializerSettings); // Assert Assert.Same(serializerSettings, jsonFormatter.SerializerSettings); } [Fact] - public async Task ChangesTo_DefaultSerializerSettings_TakesEffect() + public async Task ChangesTo_SerializerSettings_AffectSerialization() { // Arrange var person = new User() { Name = "John", Age = 35 }; - var expectedOutput = JsonConvert.SerializeObject(person, new JsonSerializerSettings() + var outputFormatterContext = GetOutputFormatterContext(person, typeof(User)); + + var settings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver(), - Formatting = Formatting.Indented - }); - - var jsonFormatter = new JsonOutputFormatter(); - jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); - jsonFormatter.SerializerSettings.Formatting = Formatting.Indented; - var outputFormatterContext = GetOutputFormatterContext(person, typeof(User)); + Formatting = Formatting.Indented, + }; + var expectedOutput = JsonConvert.SerializeObject(person, settings); + var jsonFormatter = new JsonOutputFormatter(settings, ArrayPool.Shared); // Act await jsonFormatter.WriteResponseBodyAsync(outputFormatterContext, Encoding.UTF8); @@ -79,15 +76,13 @@ namespace Microsoft.AspNetCore.Mvc.Formatters } [Fact] - public async Task ChangesTo_DefaultSerializerSettings_AfterSerialization_NoEffect() + public async Task ChangesTo_SerializerSettings_AfterSerialization_DoNotAffectSerialization() { // Arrange var person = new User() { Name = "John", Age = 35 }; - var expectedOutput = JsonConvert.SerializeObject( - person, - SerializerSettingsProvider.CreateSerializerSettings()); + var expectedOutput = JsonConvert.SerializeObject(person, new JsonSerializerSettings()); - var jsonFormatter = new JsonOutputFormatter(); + var jsonFormatter = new TestableJsonOutputFormatter(new JsonSerializerSettings()); // This will create a serializer - which gets cached. var outputFormatterContext1 = GetOutputFormatterContext(person, typeof(User)); @@ -112,84 +107,12 @@ namespace Microsoft.AspNetCore.Mvc.Formatters Assert.Equal(expectedOutput, content); } - [Fact] - public async Task ReplaceSerializerSettings_AfterSerialization_TakesEffect() - { - // Arrange - var person = new User() { Name = "John", Age = 35 }; - var expectedOutput = JsonConvert.SerializeObject(person, new JsonSerializerSettings() - { - ContractResolver = new CamelCasePropertyNamesContractResolver(), - Formatting = Formatting.Indented - }); - - var jsonFormatter = new JsonOutputFormatter(); - - // This will create a serializer - which gets cached. - var outputFormatterContext1 = GetOutputFormatterContext(person, typeof(User)); - await jsonFormatter.WriteResponseBodyAsync(outputFormatterContext1, Encoding.UTF8); - - // This results in a new serializer being created. - jsonFormatter.SerializerSettings = new JsonSerializerSettings() - { - ContractResolver = new CamelCasePropertyNamesContractResolver(), - Formatting = Formatting.Indented, - }; - - var outputFormatterContext2 = GetOutputFormatterContext(person, typeof(User)); - - // Act - await jsonFormatter.WriteResponseBodyAsync(outputFormatterContext2, Encoding.UTF8); - - // Assert - var body = outputFormatterContext2.HttpContext.Response.Body; - - Assert.NotNull(body); - body.Position = 0; - - var content = new StreamReader(body, Encoding.UTF8).ReadToEnd(); - Assert.Equal(expectedOutput, content); - } - - [Fact] - public async Task CustomSerializerSettingsObject_TakesEffect() - { - // Arrange - var person = new User() { Name = "John", Age = 35 }; - var expectedOutput = JsonConvert.SerializeObject(person, new JsonSerializerSettings() - { - ContractResolver = new CamelCasePropertyNamesContractResolver(), - Formatting = Formatting.Indented - }); - - var jsonFormatter = new JsonOutputFormatter(); - jsonFormatter.SerializerSettings = new JsonSerializerSettings() - { - ContractResolver = new CamelCasePropertyNamesContractResolver(), - Formatting = Formatting.Indented - }; - - var outputFormatterContext = GetOutputFormatterContext(person, typeof(User)); - - // Act - await jsonFormatter.WriteResponseBodyAsync(outputFormatterContext, Encoding.UTF8); - - // Assert - var body = outputFormatterContext.HttpContext.Response.Body; - - Assert.NotNull(body); - body.Position = 0; - - var content = new StreamReader(body, Encoding.UTF8).ReadToEnd(); - Assert.Equal(expectedOutput, content); - } - [Fact] public async Task WriteToStreamAsync_RoundTripsJToken() { // Arrange var beforeMessage = "Hello World"; - var formatter = new JsonOutputFormatter(); + var formatter = new JsonOutputFormatter(new JsonSerializerSettings(), ArrayPool.Shared); var before = new JValue(beforeMessage); var memStream = new MemoryStream(); var outputFormatterContext = GetOutputFormatterContext( @@ -246,7 +169,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters bool isDefaultEncoding) { // Arrange - var formatter = new JsonOutputFormatter(); + var formatter = new JsonOutputFormatter(new JsonSerializerSettings(), ArrayPool.Shared); var formattedContent = "\"" + content + "\""; var mediaType = MediaTypeHeaderValue.Parse(string.Format("application/json; charset={0}", encodingAsString)); var encoding = CreateOrGetSupportedEncoding(formatter, encodingAsString, isDefaultEncoding); @@ -334,6 +257,16 @@ namespace Microsoft.AspNetCore.Mvc.Formatters return new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor()); } + private class TestableJsonOutputFormatter : JsonOutputFormatter + { + public TestableJsonOutputFormatter(JsonSerializerSettings serializerSettings) + : base(serializerSettings, ArrayPool.Shared) + { + } + + public new JsonSerializerSettings SerializerSettings => base.SerializerSettings; + } + private sealed class User { public string Name { get; set; } diff --git a/test/Microsoft.AspNetCore.Mvc.Formatters.Json.Test/JsonPatchInputFormatterTest.cs b/test/Microsoft.AspNetCore.Mvc.Formatters.Json.Test/JsonPatchInputFormatterTest.cs index 2ea16a48fb..8ff677b73d 100644 --- a/test/Microsoft.AspNetCore.Mvc.Formatters.Json.Test/JsonPatchInputFormatterTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Formatters.Json.Test/JsonPatchInputFormatterTest.cs @@ -2,28 +2,34 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.IO; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.JsonPatch; using Microsoft.AspNetCore.Mvc.ModelBinding; -using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Testing; +using Microsoft.Extensions.ObjectPool; using Moq; +using Newtonsoft.Json; using Xunit; namespace Microsoft.AspNetCore.Mvc.Formatters { public class JsonPatchInputFormatterTest { + private static readonly ObjectPoolProvider _objectPoolProvider = new DefaultObjectPoolProvider(); + private static readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings(); + [Fact] public async Task JsonPatchInputFormatter_ReadsOneOperation_Successfully() { // Arrange var logger = GetLogger(); - var formatter = new JsonPatchInputFormatter(logger); + var formatter = + new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool.Shared, _objectPoolProvider); var content = "[{\"op\":\"add\",\"path\":\"Customer/Name\",\"value\":\"John\"}]"; var contentBytes = Encoding.UTF8.GetBytes(content); @@ -54,7 +60,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters { // Arrange var logger = GetLogger(); - var formatter = new JsonPatchInputFormatter(logger); + var formatter = + new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool.Shared, _objectPoolProvider); var content = "[{\"op\": \"add\", \"path\" : \"Customer/Name\", \"value\":\"John\"}," + "{\"op\": \"remove\", \"path\" : \"Customer/Name\"}]"; var contentBytes = Encoding.UTF8.GetBytes(content); @@ -92,7 +99,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters { // Arrange var logger = GetLogger(); - var formatter = new JsonPatchInputFormatter(logger); + var formatter = + new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool.Shared, _objectPoolProvider); var content = "[{\"op\": \"add\", \"path\" : \"Customer/Name\", \"value\":\"John\"}]"; var contentBytes = Encoding.UTF8.GetBytes(content); @@ -121,7 +129,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters { // Arrange var logger = GetLogger(); - var formatter = new JsonPatchInputFormatter(logger); + var formatter = + new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool.Shared, _objectPoolProvider); var content = "[{\"op\": \"add\", \"path\" : \"Customer/Name\", \"value\":\"John\"}]"; var contentBytes = Encoding.UTF8.GetBytes(content); @@ -151,7 +160,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters $"'{typeof(Customer).FullName}' because the type requires a JSON object "; var logger = GetLogger(); - var formatter = new JsonPatchInputFormatter(logger); + var formatter = + new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool.Shared, _objectPoolProvider); var content = "[{\"op\": \"add\", \"path\" : \"Customer/Name\", \"value\":\"John\"}]"; var contentBytes = Encoding.UTF8.GetBytes(content); diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/BasicTests.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/BasicTests.cs index 3dafb33608..a32957716c 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/BasicTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/BasicTests.cs @@ -7,7 +7,6 @@ using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Reflection; -using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; @@ -248,11 +247,13 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests public async Task JsonHelperWithSettings_RendersJson() { // Arrange - var json = JsonConvert.SerializeObject(new BasicWebSite.Models.Person() - { - Id = 9000, - Name = "John Smith" - }, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }); + var json = JsonConvert.SerializeObject( + new BasicWebSite.Models.Person() + { + Id = 9000, + Name = "John Smith" + }, + new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }); var expectedBody = string.Format( @" \ No newline at end of file diff --git a/test/WebSites/FiltersWebSite/Controllers/ResourceFilterController.cs b/test/WebSites/FiltersWebSite/Controllers/ResourceFilterController.cs index d48cc54f4b..1fd3f7456e 100644 --- a/test/WebSites/FiltersWebSite/Controllers/ResourceFilterController.cs +++ b/test/WebSites/FiltersWebSite/Controllers/ResourceFilterController.cs @@ -2,9 +2,12 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Linq; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Formatters; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; namespace FiltersWebSite.Controllers { @@ -27,24 +30,16 @@ namespace FiltersWebSite.Controllers private class ShortCircuitWithFormatterAttribute : Attribute, IResourceFilter { - private IOutputFormatter[] _formatters; - - public ShortCircuitWithFormatterAttribute() - { - _formatters = new IOutputFormatter[] { new JsonOutputFormatter() }; - } - public void OnResourceExecuted(ResourceExecutedContext context) { } public void OnResourceExecuting(ResourceExecutingContext context) { + var mvcOptions = context.HttpContext.RequestServices.GetRequiredService>(); + var formatter = mvcOptions.Value.OutputFormatters.OfType().First(); var result = new ObjectResult("someValue"); - foreach (var formatter in _formatters) - { - result.Formatters.Add(formatter); - } + result.Formatters.Add(formatter); context.Result = result; } diff --git a/test/WebSites/FormatterWebSite/Controllers/JsonFormatterController.cs b/test/WebSites/FormatterWebSite/Controllers/JsonFormatterController.cs index 88b4e0e7c0..fd8101faab 100644 --- a/test/WebSites/FormatterWebSite/Controllers/JsonFormatterController.cs +++ b/test/WebSites/FormatterWebSite/Controllers/JsonFormatterController.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Buffers; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Formatters; @@ -10,6 +11,20 @@ namespace FormatterWebSite.Controllers { public class JsonFormatterController : Controller { + private static readonly JsonSerializerSettings _indentedSettings; + private readonly JsonOutputFormatter _indentingFormatter; + + static JsonFormatterController() + { + _indentedSettings = JsonSerializerSettingsProvider.CreateSerializerSettings(); + _indentedSettings.Formatting = Formatting.Indented; + } + + public JsonFormatterController(ArrayPool charPool) + { + _indentingFormatter = new JsonOutputFormatter(_indentedSettings, charPool); + } + public IActionResult ReturnsIndentedJson() { var user = new User() @@ -21,11 +36,8 @@ namespace FormatterWebSite.Controllers Name = "John Williams" }; - var jsonFormatter = new JsonOutputFormatter(); - jsonFormatter.SerializerSettings.Formatting = Formatting.Indented; - var objectResult = new ObjectResult(user); - objectResult.Formatters.Add(jsonFormatter); + objectResult.Formatters.Add(_indentingFormatter); return objectResult; } diff --git a/test/WebSites/WebApiCompatShimWebSite/Controllers/ActionResults/ActionResultController.cs b/test/WebSites/WebApiCompatShimWebSite/Controllers/ActionResults/ActionResultController.cs index 66aba5b987..0b3c694008 100644 --- a/test/WebSites/WebApiCompatShimWebSite/Controllers/ActionResults/ActionResultController.cs +++ b/test/WebSites/WebApiCompatShimWebSite/Controllers/ActionResults/ActionResultController.cs @@ -7,12 +7,21 @@ using System.Net.Http; using System.Text; using System.Web.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Formatters; using Newtonsoft.Json; namespace WebApiCompatShimWebSite { public class ActionResultController : ApiController { + private static readonly JsonSerializerSettings _indentedSettings; + + static ActionResultController() + { + _indentedSettings = JsonSerializerSettingsProvider.CreateSerializerSettings(); + _indentedSettings.Formatting = Formatting.Indented; + } + public IActionResult GetBadRequest() { return BadRequest(); @@ -82,15 +91,12 @@ namespace WebApiCompatShimWebSite public IActionResult GetJsonSettings() { - return Json(CreateUser(), new JsonSerializerSettings() { Formatting = Formatting.Indented }); + return Json(CreateUser(), _indentedSettings); } public IActionResult GetJsonSettingsEncoding() { - return Json( - CreateUser(), - new JsonSerializerSettings() { Formatting = Formatting.Indented }, - Encoding.UTF32); + return Json(CreateUser(), _indentedSettings, Encoding.UTF32); } public IActionResult GetNotFound()