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
This commit is contained in:
Doug Bunting 2016-04-16 18:19:48 -07:00
parent cbcae3f4e5
commit d8d2e54506
32 changed files with 304 additions and 360 deletions

View File

@ -14,7 +14,7 @@ using Newtonsoft.Json;
namespace Microsoft.AspNetCore.Mvc.Formatters namespace Microsoft.AspNetCore.Mvc.Formatters
{ {
/// <summary> /// <summary>
/// An <see cref="TextInputFormatter"/> for JSON content. /// A <see cref="TextInputFormatter"/> for JSON content.
/// </summary> /// </summary>
public class JsonInputFormatter : TextInputFormatter public class JsonInputFormatter : TextInputFormatter
{ {
@ -22,36 +22,16 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly ObjectPoolProvider _objectPoolProvider; private readonly ObjectPoolProvider _objectPoolProvider;
private ObjectPool<JsonSerializer> _jsonSerializerPool; private ObjectPool<JsonSerializer> _jsonSerializerPool;
private JsonSerializerSettings _serializerSettings;
/// <summary> /// <summary>
/// Initializes a new instance of <see cref="JsonInputFormatter"/>. /// Initializes a new instance of <see cref="JsonInputFormatter"/>.
/// </summary> /// </summary>
/// <param name="logger">The <see cref="ILogger"/>.</param> /// <param name="logger">The <see cref="ILogger"/>.</param>
public JsonInputFormatter(ILogger logger) /// <param name="serializerSettings">
: this(logger, SerializerSettingsProvider.CreateSerializerSettings()) /// The <see cref="JsonSerializerSettings"/>. Should be either the application-wide settings
{ /// (<see cref="MvcJsonOptions.SerializerSettings"/>) or an instance
} /// <see cref="JsonSerializerSettingsProvider.CreateSerializerSettings"/> initially returned.
/// </param>
/// <summary>
/// Initializes a new instance of <see cref="JsonInputFormatter"/>.
/// </summary>
/// <param name="logger">The <see cref="ILogger"/>.</param>
/// <param name="serializerSettings">The <see cref="JsonSerializerSettings"/>.</param>
public JsonInputFormatter(ILogger logger, JsonSerializerSettings serializerSettings)
: this(
logger,
serializerSettings,
ArrayPool<char>.Shared,
new DefaultObjectPoolProvider())
{
}
/// <summary>
/// Initializes a new instance of <see cref="JsonInputFormatter"/>.
/// </summary>
/// <param name="logger">The <see cref="ILogger"/>.</param>
/// <param name="serializerSettings">The <see cref="JsonSerializerSettings"/>.</param>
/// <param name="charPool">The <see cref="ArrayPool{Char}"/>.</param> /// <param name="charPool">The <see cref="ArrayPool{Char}"/>.</param>
/// <param name="objectPoolProvider">The <see cref="ObjectPoolProvider"/>.</param> /// <param name="objectPoolProvider">The <see cref="ObjectPoolProvider"/>.</param>
public JsonInputFormatter( public JsonInputFormatter(
@ -81,7 +61,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
} }
_logger = logger; _logger = logger;
_serializerSettings = serializerSettings; SerializerSettings = serializerSettings;
_charPool = new JsonArrayPool<char>(charPool); _charPool = new JsonArrayPool<char>(charPool);
_objectPoolProvider = objectPoolProvider; _objectPoolProvider = objectPoolProvider;
@ -93,28 +73,13 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
} }
/// <summary> /// <summary>
/// Gets or sets the <see cref="JsonSerializerSettings"/> used to configure the <see cref="JsonSerializer"/>. /// Gets the <see cref="JsonSerializerSettings"/> used to configure the <see cref="JsonSerializer"/>.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Any modifications to the <see cref="JsonSerializerSettings"/> object after this /// Any modifications to the <see cref="JsonSerializerSettings"/> object after this
/// <see cref="JsonInputFormatter"/> has been used will have no effect. /// <see cref="JsonInputFormatter"/> has been used will have no effect.
/// </remarks> /// </remarks>
public JsonSerializerSettings SerializerSettings protected JsonSerializerSettings SerializerSettings { get; }
{
get
{
return _serializerSettings;
}
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
_serializerSettings = value;
}
}
/// <inheritdoc /> /// <inheritdoc />
public override Task<InputFormatterResult> ReadRequestBodyAsync( public override Task<InputFormatterResult> ReadRequestBodyAsync(

View File

@ -7,34 +7,30 @@ using System.IO;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Formatters.Json.Internal; using Microsoft.AspNetCore.Mvc.Formatters.Json.Internal;
using Microsoft.AspNetCore.Mvc.Internal;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Microsoft.AspNetCore.Mvc.Formatters namespace Microsoft.AspNetCore.Mvc.Formatters
{ {
/// <summary> /// <summary>
/// An output formatter that specializes in writing JSON content. /// A <see cref="TextOutputFormatter"/> for JSON content.
/// </summary> /// </summary>
public class JsonOutputFormatter : TextOutputFormatter public class JsonOutputFormatter : TextOutputFormatter
{ {
private readonly IArrayPool<char> _charPool; private readonly IArrayPool<char> _charPool;
private JsonSerializerSettings _serializerSettings;
// Perf: JsonSerializers are relatively expensive to create, and are thread safe. We cache // Perf: JsonSerializers are relatively expensive to create, and are thread safe. We cache
// the serializer and invalidate it when the settings change. // the serializer and invalidate it when the settings change.
private JsonSerializer _serializer; private JsonSerializer _serializer;
public JsonOutputFormatter() /// <summary>
: this(SerializerSettingsProvider.CreateSerializerSettings(), ArrayPool<char>.Shared) /// Initializes a new <see cref="JsonOutputFormatter"/> instance.
{ /// </summary>
} /// <param name="serializerSettings">
/// The <see cref="JsonSerializerSettings"/>. Should be either the application-wide settings
public JsonOutputFormatter(JsonSerializerSettings serializerSettings) /// (<see cref="MvcJsonOptions.SerializerSettings"/>) or an instance
: this(serializerSettings, ArrayPool<char>.Shared) /// <see cref="JsonSerializerSettingsProvider.CreateSerializerSettings"/> initially returned.
{ /// </param>
} /// <param name="charPool">The <see cref="ArrayPool{Char}"/>.</param>
public JsonOutputFormatter(JsonSerializerSettings serializerSettings, ArrayPool<char> charPool) public JsonOutputFormatter(JsonSerializerSettings serializerSettings, ArrayPool<char> charPool)
{ {
if (serializerSettings == null) if (serializerSettings == null)
@ -47,7 +43,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
throw new ArgumentNullException(nameof(charPool)); throw new ArgumentNullException(nameof(charPool));
} }
_serializerSettings = serializerSettings; SerializerSettings = serializerSettings;
_charPool = new JsonArrayPool<char>(charPool); _charPool = new JsonArrayPool<char>(charPool);
SupportedEncodings.Add(Encoding.UTF8); SupportedEncodings.Add(Encoding.UTF8);
@ -57,31 +53,13 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
} }
/// <summary> /// <summary>
/// Gets or sets the <see cref="JsonSerializerSettings"/> used to configure the <see cref="JsonSerializer"/>. /// Gets the <see cref="JsonSerializerSettings"/> used to configure the <see cref="JsonSerializer"/>.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Any modifications to the <see cref="JsonSerializerSettings"/> object after this /// Any modifications to the <see cref="JsonSerializerSettings"/> object after this
/// <see cref="JsonOutputFormatter"/> has been used will have no effect. /// <see cref="JsonOutputFormatter"/> has been used will have no effect.
/// </remarks> /// </remarks>
public JsonSerializerSettings SerializerSettings protected JsonSerializerSettings SerializerSettings { get; }
{
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;
}
}
/// <summary> /// <summary>
/// Writes the given <paramref name="value"/> as JSON using the given /// Writes the given <paramref name="value"/> as JSON using the given

View File

@ -14,17 +14,21 @@ using Newtonsoft.Json;
namespace Microsoft.AspNetCore.Mvc.Formatters namespace Microsoft.AspNetCore.Mvc.Formatters
{ {
/// <summary>
/// A <see cref="TextInputFormatter"/> for JSON Patch (application/json-patch+json) content.
/// </summary>
public class JsonPatchInputFormatter : JsonInputFormatter public class JsonPatchInputFormatter : JsonInputFormatter
{ {
public JsonPatchInputFormatter(ILogger logger) /// <summary>
: this( /// Initializes a new <see cref="JsonPatchInputFormatter"/> instance.
logger, /// </summary>
SerializerSettingsProvider.CreateSerializerSettings(), /// <param name="logger">The <see cref="ILogger"/>.</param>
ArrayPool<char>.Shared, /// <param name="serializerSettings">
new DefaultObjectPoolProvider()) /// The <see cref="JsonSerializerSettings"/>. Should be either the application-wide settings
{ /// (<see cref="MvcJsonOptions.SerializerSettings"/>) or an instance
} /// <see cref="JsonSerializerSettingsProvider.CreateSerializerSettings"/> initially returned.
/// </param>/// <param name="charPool">The <see cref="ArrayPool{Char}"/>.</param>
/// <param name="objectPoolProvider">The <see cref="ObjectPoolProvider"/>.</param>
public JsonPatchInputFormatter( public JsonPatchInputFormatter(
ILogger logger, ILogger logger,
JsonSerializerSettings serializerSettings, JsonSerializerSettings serializerSettings,

View File

@ -3,12 +3,12 @@
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Microsoft.AspNetCore.Mvc.Formatters.Json.Internal namespace Microsoft.AspNetCore.Mvc.Formatters
{ {
/// <summary> /// <summary>
/// Helper class which provides <see cref="JsonSerializerSettings"/>. /// Helper class which provides <see cref="JsonSerializerSettings"/>.
/// </summary> /// </summary>
public static class SerializerSettingsProvider public static class JsonSerializerSettingsProvider
{ {
private const int DefaultMaxDepth = 32; private const int DefaultMaxDepth = 32;

View File

@ -1,7 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // 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; using Newtonsoft.Json;
namespace Microsoft.AspNetCore.Mvc namespace Microsoft.AspNetCore.Mvc
@ -14,6 +14,7 @@ namespace Microsoft.AspNetCore.Mvc
/// <summary> /// <summary>
/// Gets the <see cref="JsonSerializerSettings"/> that are used by this application. /// Gets the <see cref="JsonSerializerSettings"/> that are used by this application.
/// </summary> /// </summary>
public JsonSerializerSettings SerializerSettings { get; } = SerializerSettingsProvider.CreateSerializerSettings(); public JsonSerializerSettings SerializerSettings { get; } =
JsonSerializerSettingsProvider.CreateSerializerSettings();
} }
} }

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Buffers;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Html;
@ -17,19 +18,29 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
public class JsonHelper : IJsonHelper public class JsonHelper : IJsonHelper
{ {
private readonly JsonOutputFormatter _jsonOutputFormatter; private readonly JsonOutputFormatter _jsonOutputFormatter;
private readonly ArrayPool<char> _charPool;
/// <summary> /// <summary>
/// Initializes a new instance of <see cref="JsonHelper"/> that is backed by <paramref name="jsonOutputFormatter"/>. /// Initializes a new instance of <see cref="JsonHelper"/> that is backed by <paramref name="jsonOutputFormatter"/>.
/// </summary> /// </summary>
/// <param name="jsonOutputFormatter">The <see cref="JsonOutputFormatter"/> used to serialize JSON.</param> /// <param name="jsonOutputFormatter">The <see cref="JsonOutputFormatter"/> used to serialize JSON.</param>
public JsonHelper(JsonOutputFormatter jsonOutputFormatter) /// <param name="charPool">
/// The <see cref="ArrayPool{Char}"/> for use with custom <see cref="JsonSerializerSettings"/> (see
/// <see cref="Serialize(object, JsonSerializerSettings)"/>).
/// </param>
public JsonHelper(JsonOutputFormatter jsonOutputFormatter, ArrayPool<char> charPool)
{ {
if (jsonOutputFormatter == null) if (jsonOutputFormatter == null)
{ {
throw new ArgumentNullException(nameof(jsonOutputFormatter)); throw new ArgumentNullException(nameof(jsonOutputFormatter));
} }
if (charPool == null)
{
throw new ArgumentNullException(nameof(charPool));
}
_jsonOutputFormatter = jsonOutputFormatter; _jsonOutputFormatter = jsonOutputFormatter;
_charPool = charPool;
} }
/// <inheritdoc /> /// <inheritdoc />
@ -46,7 +57,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
throw new ArgumentNullException(nameof(serializerSettings)); throw new ArgumentNullException(nameof(serializerSettings));
} }
var jsonOutputFormatter = new JsonOutputFormatter(serializerSettings); var jsonOutputFormatter = new JsonOutputFormatter(serializerSettings, _charPool);
return SerializeInternal(jsonOutputFormatter, value); return SerializeInternal(jsonOutputFormatter, value);
} }

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Buffers;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
@ -14,6 +15,7 @@ using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Logging.Testing;
using Moq; using Moq;
using Newtonsoft.Json;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Mvc namespace Microsoft.AspNetCore.Mvc
@ -88,7 +90,9 @@ namespace Microsoft.AspNetCore.Mvc
{ {
var options = new TestOptionsManager<MvcOptions>(); var options = new TestOptionsManager<MvcOptions>();
options.Value.OutputFormatters.Add(new StringOutputFormatter()); options.Value.OutputFormatters.Add(new StringOutputFormatter());
options.Value.OutputFormatters.Add(new JsonOutputFormatter()); options.Value.OutputFormatters.Add(new JsonOutputFormatter(
new JsonSerializerSettings(),
ArrayPool<char>.Shared));
var services = new ServiceCollection(); var services = new ServiceCollection();
services.AddSingleton(new ObjectResultExecutor( services.AddSingleton(new ObjectResultExecutor(

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -14,6 +15,7 @@ using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Logging.Testing;
using Moq; using Moq;
using Newtonsoft.Json;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Mvc namespace Microsoft.AspNetCore.Mvc
@ -103,7 +105,9 @@ namespace Microsoft.AspNetCore.Mvc
{ {
var options = new TestOptionsManager<MvcOptions>(); var options = new TestOptionsManager<MvcOptions>();
options.Value.OutputFormatters.Add(new StringOutputFormatter()); options.Value.OutputFormatters.Add(new StringOutputFormatter());
options.Value.OutputFormatters.Add(new JsonOutputFormatter()); options.Value.OutputFormatters.Add(new JsonOutputFormatter(
new JsonSerializerSettings(),
ArrayPool<char>.Shared));
var services = new ServiceCollection(); var services = new ServiceCollection();
services.AddSingleton(new ObjectResultExecutor( services.AddSingleton(new ObjectResultExecutor(

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Buffers;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
@ -12,6 +13,7 @@ using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Logging.Testing;
using Moq; using Moq;
using Newtonsoft.Json;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Mvc namespace Microsoft.AspNetCore.Mvc
@ -89,7 +91,9 @@ namespace Microsoft.AspNetCore.Mvc
{ {
var options = new TestOptionsManager<MvcOptions>(); var options = new TestOptionsManager<MvcOptions>();
options.Value.OutputFormatters.Add(new StringOutputFormatter()); options.Value.OutputFormatters.Add(new StringOutputFormatter());
options.Value.OutputFormatters.Add(new JsonOutputFormatter()); options.Value.OutputFormatters.Add(new JsonOutputFormatter(
new JsonSerializerSettings(),
ArrayPool<char>.Shared));
var services = new ServiceCollection(); var services = new ServiceCollection();
services.AddSingleton(new ObjectResultExecutor( services.AddSingleton(new ObjectResultExecutor(

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // 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.Http;
using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
@ -10,6 +11,7 @@ using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
using Moq; using Moq;
using Newtonsoft.Json;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Mvc.Formatters namespace Microsoft.AspNetCore.Mvc.Formatters
@ -442,7 +444,9 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
// Set up default output formatters. // Set up default output formatters.
Options.OutputFormatters.Add(new HttpNoContentOutputFormatter()); Options.OutputFormatters.Add(new HttpNoContentOutputFormatter());
Options.OutputFormatters.Add(new StringOutputFormatter()); Options.OutputFormatters.Add(new StringOutputFormatter());
Options.OutputFormatters.Add(new JsonOutputFormatter()); Options.OutputFormatters.Add(new JsonOutputFormatter(
new JsonSerializerSettings(),
ArrayPool<char>.Shared));
// Set up default mapping for json extensions to content type // Set up default mapping for json extensions to content type
Options.FormatterMappings.SetMediaTypeMappingForFormat( Options.FormatterMappings.SetMediaTypeMappingForFormat(

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Buffers;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
@ -9,6 +10,7 @@ using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc.Internal; using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Logging.Testing;
using Newtonsoft.Json;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Mvc namespace Microsoft.AspNetCore.Mvc
@ -68,7 +70,9 @@ namespace Microsoft.AspNetCore.Mvc
{ {
var options = new TestOptionsManager<MvcOptions>(); var options = new TestOptionsManager<MvcOptions>();
options.Value.OutputFormatters.Add(new StringOutputFormatter()); options.Value.OutputFormatters.Add(new StringOutputFormatter());
options.Value.OutputFormatters.Add(new JsonOutputFormatter()); options.Value.OutputFormatters.Add(new JsonOutputFormatter(
new JsonSerializerSettings(),
ArrayPool<char>.Shared));
var services = new ServiceCollection(); var services = new ServiceCollection();
services.AddSingleton(new ObjectResultExecutor( services.AddSingleton(new ObjectResultExecutor(

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Buffers;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Abstractions;
@ -10,6 +11,7 @@ using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Logging.Testing;
using Newtonsoft.Json;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Mvc namespace Microsoft.AspNetCore.Mvc
@ -69,7 +71,9 @@ namespace Microsoft.AspNetCore.Mvc
{ {
var options = new TestOptionsManager<MvcOptions>(); var options = new TestOptionsManager<MvcOptions>();
options.Value.OutputFormatters.Add(new StringOutputFormatter()); options.Value.OutputFormatters.Add(new StringOutputFormatter());
options.Value.OutputFormatters.Add(new JsonOutputFormatter()); options.Value.OutputFormatters.Add(new JsonOutputFormatter(
new JsonSerializerSettings(),
ArrayPool<char>.Shared));
var services = new ServiceCollection(); var services = new ServiceCollection();
services.AddSingleton(new ObjectResultExecutor( services.AddSingleton(new ObjectResultExecutor(

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -11,6 +12,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Logging.Testing;
using Microsoft.Extensions.ObjectPool;
using Moq; using Moq;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Serialization;
@ -20,6 +22,9 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
{ {
public class JsonInputFormatterTest public class JsonInputFormatterTest
{ {
private static readonly ObjectPoolProvider _objectPoolProvider = new DefaultObjectPoolProvider();
private static readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings();
[Theory] [Theory]
[InlineData("application/json", true)] [InlineData("application/json", true)]
[InlineData("application/*", false)] [InlineData("application/*", false)]
@ -36,7 +41,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
// Arrange // Arrange
var loggerMock = GetLogger(); var loggerMock = GetLogger();
var formatter = new JsonInputFormatter(loggerMock); var formatter =
new JsonInputFormatter(loggerMock, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
var contentBytes = Encoding.UTF8.GetBytes("content"); var contentBytes = Encoding.UTF8.GetBytes("content");
var httpContext = GetHttpContext(contentBytes, contentType: requestContentType); var httpContext = GetHttpContext(contentBytes, contentType: requestContentType);
@ -61,7 +67,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
{ {
// Arrange // Arrange
var loggerMock = GetLogger(); var loggerMock = GetLogger();
var formatter = new JsonInputFormatter(loggerMock); var formatter =
new JsonInputFormatter(loggerMock, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
// Act // Act
var mediaType = formatter.SupportedMediaTypes[0]; var mediaType = formatter.SupportedMediaTypes[0];
@ -87,7 +94,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
{ {
// Arrange // Arrange
var logger = GetLogger(); var logger = GetLogger();
var formatter = new JsonInputFormatter(logger); var formatter =
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
var contentBytes = Encoding.UTF8.GetBytes(content); var contentBytes = Encoding.UTF8.GetBytes(content);
var httpContext = GetHttpContext(contentBytes); var httpContext = GetHttpContext(contentBytes);
@ -114,7 +122,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
// Arrange // Arrange
var content = "{name: 'Person Name', Age: '30'}"; var content = "{name: 'Person Name', Age: '30'}";
var logger = GetLogger(); var logger = GetLogger();
var formatter = new JsonInputFormatter(logger); var formatter =
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
var contentBytes = Encoding.UTF8.GetBytes(content); var contentBytes = Encoding.UTF8.GetBytes(content);
var httpContext = GetHttpContext(contentBytes); var httpContext = GetHttpContext(contentBytes);
@ -143,7 +152,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
// Arrange // Arrange
var content = "[0, 23, 300]"; var content = "[0, 23, 300]";
var logger = GetLogger(); var logger = GetLogger();
var formatter = new JsonInputFormatter(logger); var formatter =
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
var contentBytes = Encoding.UTF8.GetBytes(content); var contentBytes = Encoding.UTF8.GetBytes(content);
var modelState = new ModelStateDictionary(); var modelState = new ModelStateDictionary();
@ -176,7 +186,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
// Arrange // Arrange
var content = "[0, 23, 300]"; var content = "[0, 23, 300]";
var logger = GetLogger(); var logger = GetLogger();
var formatter = new JsonInputFormatter(logger); var formatter =
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
var contentBytes = Encoding.UTF8.GetBytes(content); var contentBytes = Encoding.UTF8.GetBytes(content);
var modelState = new ModelStateDictionary(); var modelState = new ModelStateDictionary();
@ -205,7 +216,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
// Arrange // Arrange
var content = "{name: 'Person Name', Age: 'not-an-age'}"; var content = "{name: 'Person Name', Age: 'not-an-age'}";
var logger = GetLogger(); var logger = GetLogger();
var formatter = new JsonInputFormatter(logger); var formatter =
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
var contentBytes = Encoding.UTF8.GetBytes(content); var contentBytes = Encoding.UTF8.GetBytes(content);
var modelState = new ModelStateDictionary(); var modelState = new ModelStateDictionary();
@ -235,7 +247,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
// Arrange // Arrange
var content = "[0, 23, 300]"; var content = "[0, 23, 300]";
var logger = GetLogger(); var logger = GetLogger();
var formatter = new JsonInputFormatter(logger); var formatter =
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
var contentBytes = Encoding.UTF8.GetBytes(content); var contentBytes = Encoding.UTF8.GetBytes(content);
var modelState = new ModelStateDictionary(); var modelState = new ModelStateDictionary();
@ -264,7 +277,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
// Arrange // Arrange
var content = "[{name: 'Name One', Age: 30}, {name: 'Name Two', Small: 300}]"; var content = "[{name: 'Name One', Age: 30}, {name: 'Name Two', Small: 300}]";
var logger = GetLogger(); var logger = GetLogger();
var formatter = new JsonInputFormatter(logger); var formatter =
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
var contentBytes = Encoding.UTF8.GetBytes(content); var contentBytes = Encoding.UTF8.GetBytes(content);
var modelState = new ModelStateDictionary(); var modelState = new ModelStateDictionary();
@ -294,7 +308,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
// Arrange // Arrange
var content = "{name: 'Person Name', Age: 'not-an-age'}"; var content = "{name: 'Person Name', Age: 'not-an-age'}";
var logger = GetLogger(); var logger = GetLogger();
var formatter = new JsonInputFormatter(logger); var formatter =
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
var contentBytes = Encoding.UTF8.GetBytes(content); var contentBytes = Encoding.UTF8.GetBytes(content);
var modelState = new ModelStateDictionary(); var modelState = new ModelStateDictionary();
@ -322,66 +337,19 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
Assert.IsType<TooManyModelErrorsException>(error.Exception); Assert.IsType<TooManyModelErrorsException>(error.Exception);
} }
[Fact]
public void Creates_SerializerSettings_ByDefault()
{
// Arrange
var logger = GetLogger();
// Act
var jsonFormatter = new JsonInputFormatter(logger);
// Assert
Assert.NotNull(jsonFormatter.SerializerSettings);
}
[Fact] [Fact]
public void Constructor_UsesSerializerSettings() public void Constructor_UsesSerializerSettings()
{ {
// Arrange // Arrange
var logger = GetLogger(); var serializerSettings = new JsonSerializerSettings();
// Act // Act
var serializerSettings = new JsonSerializerSettings(); var jsonFormatter = new TestableJsonInputFormatter(serializerSettings);
var jsonFormatter = new JsonInputFormatter(logger, serializerSettings);
// Assert // Assert
Assert.Same(serializerSettings, jsonFormatter.SerializerSettings); 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] [Fact]
public async Task CustomSerializerSettingsObject_TakesEffect() public async Task CustomSerializerSettingsObject_TakesEffect()
{ {
@ -389,12 +357,11 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
// missing password property here // missing password property here
var contentBytes = Encoding.UTF8.GetBytes("{ \"UserName\" : \"John\"}"); var contentBytes = Encoding.UTF8.GetBytes("{ \"UserName\" : \"John\"}");
var logger = GetLogger(); var logger = GetLogger();
var jsonFormatter = new JsonInputFormatter(logger);
// by default we ignore missing members, so here explicitly changing it // by default we ignore missing members, so here explicitly changing it
jsonFormatter.SerializerSettings = new JsonSerializerSettings() var serializerSettings = new JsonSerializerSettings { MissingMemberHandling = MissingMemberHandling.Error };
{ var jsonFormatter =
MissingMemberHandling = MissingMemberHandling.Error new JsonInputFormatter(logger, serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
};
var modelState = new ModelStateDictionary(); var modelState = new ModelStateDictionary();
var httpContext = GetHttpContext(contentBytes, "application/json;charset=utf-8"); var httpContext = GetHttpContext(contentBytes, "application/json;charset=utf-8");
@ -428,7 +395,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
MaxDepth = 2, MaxDepth = 2,
DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind, DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind,
}; };
var formatter = new TestableJsonInputFormatter(GetLogger(), settings); var formatter = new TestableJsonInputFormatter(settings);
// Act // Act
var actual = formatter.CreateJsonSerializer(); var actual = formatter.CreateJsonSerializer();
@ -441,11 +408,13 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
private class TestableJsonInputFormatter : JsonInputFormatter private class TestableJsonInputFormatter : JsonInputFormatter
{ {
public TestableJsonInputFormatter(ILogger logger, JsonSerializerSettings settings) public TestableJsonInputFormatter(JsonSerializerSettings settings)
: base(logger, settings) : base(GetLogger(), settings, ArrayPool<char>.Shared, _objectPoolProvider)
{ {
} }
public new JsonSerializerSettings SerializerSettings => base.SerializerSettings;
public new JsonSerializer CreateJsonSerializer() => base.CreateJsonSerializer(); public new JsonSerializer CreateJsonSerializer() => base.CreateJsonSerializer();
} }

View File

@ -2,13 +2,13 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Buffers;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Formatters.Json.Internal;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -28,9 +28,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
[Fact] [Fact]
public void Creates_SerializerSettings_ByDefault() public void Creates_SerializerSettings_ByDefault()
{ {
// Arrange // Arrange & Act
// Act var jsonFormatter = new TestableJsonOutputFormatter(new JsonSerializerSettings());
var jsonFormatter = new JsonOutputFormatter();
// Assert // Assert
Assert.NotNull(jsonFormatter.SerializerSettings); Assert.NotNull(jsonFormatter.SerializerSettings);
@ -42,28 +41,26 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
// Arrange // Arrange
// Act // Act
var serializerSettings = new JsonSerializerSettings(); var serializerSettings = new JsonSerializerSettings();
var logger = GetLogger(); var jsonFormatter = new TestableJsonOutputFormatter(serializerSettings);
var jsonFormatter = new JsonInputFormatter(logger, serializerSettings);
// Assert // Assert
Assert.Same(serializerSettings, jsonFormatter.SerializerSettings); Assert.Same(serializerSettings, jsonFormatter.SerializerSettings);
} }
[Fact] [Fact]
public async Task ChangesTo_DefaultSerializerSettings_TakesEffect() public async Task ChangesTo_SerializerSettings_AffectSerialization()
{ {
// Arrange // Arrange
var person = new User() { Name = "John", Age = 35 }; 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(), ContractResolver = new CamelCasePropertyNamesContractResolver(),
Formatting = Formatting.Indented Formatting = Formatting.Indented,
}); };
var expectedOutput = JsonConvert.SerializeObject(person, settings);
var jsonFormatter = new JsonOutputFormatter(); var jsonFormatter = new JsonOutputFormatter(settings, ArrayPool<char>.Shared);
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
jsonFormatter.SerializerSettings.Formatting = Formatting.Indented;
var outputFormatterContext = GetOutputFormatterContext(person, typeof(User));
// Act // Act
await jsonFormatter.WriteResponseBodyAsync(outputFormatterContext, Encoding.UTF8); await jsonFormatter.WriteResponseBodyAsync(outputFormatterContext, Encoding.UTF8);
@ -79,15 +76,13 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
} }
[Fact] [Fact]
public async Task ChangesTo_DefaultSerializerSettings_AfterSerialization_NoEffect() public async Task ChangesTo_SerializerSettings_AfterSerialization_DoNotAffectSerialization()
{ {
// Arrange // Arrange
var person = new User() { Name = "John", Age = 35 }; var person = new User() { Name = "John", Age = 35 };
var expectedOutput = JsonConvert.SerializeObject( var expectedOutput = JsonConvert.SerializeObject(person, new JsonSerializerSettings());
person,
SerializerSettingsProvider.CreateSerializerSettings());
var jsonFormatter = new JsonOutputFormatter(); var jsonFormatter = new TestableJsonOutputFormatter(new JsonSerializerSettings());
// This will create a serializer - which gets cached. // This will create a serializer - which gets cached.
var outputFormatterContext1 = GetOutputFormatterContext(person, typeof(User)); var outputFormatterContext1 = GetOutputFormatterContext(person, typeof(User));
@ -112,84 +107,12 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
Assert.Equal(expectedOutput, content); 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] [Fact]
public async Task WriteToStreamAsync_RoundTripsJToken() public async Task WriteToStreamAsync_RoundTripsJToken()
{ {
// Arrange // Arrange
var beforeMessage = "Hello World"; var beforeMessage = "Hello World";
var formatter = new JsonOutputFormatter(); var formatter = new JsonOutputFormatter(new JsonSerializerSettings(), ArrayPool<char>.Shared);
var before = new JValue(beforeMessage); var before = new JValue(beforeMessage);
var memStream = new MemoryStream(); var memStream = new MemoryStream();
var outputFormatterContext = GetOutputFormatterContext( var outputFormatterContext = GetOutputFormatterContext(
@ -246,7 +169,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
bool isDefaultEncoding) bool isDefaultEncoding)
{ {
// Arrange // Arrange
var formatter = new JsonOutputFormatter(); var formatter = new JsonOutputFormatter(new JsonSerializerSettings(), ArrayPool<char>.Shared);
var formattedContent = "\"" + content + "\""; var formattedContent = "\"" + content + "\"";
var mediaType = MediaTypeHeaderValue.Parse(string.Format("application/json; charset={0}", encodingAsString)); var mediaType = MediaTypeHeaderValue.Parse(string.Format("application/json; charset={0}", encodingAsString));
var encoding = CreateOrGetSupportedEncoding(formatter, encodingAsString, isDefaultEncoding); var encoding = CreateOrGetSupportedEncoding(formatter, encodingAsString, isDefaultEncoding);
@ -334,6 +257,16 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
return new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor()); return new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor());
} }
private class TestableJsonOutputFormatter : JsonOutputFormatter
{
public TestableJsonOutputFormatter(JsonSerializerSettings serializerSettings)
: base(serializerSettings, ArrayPool<char>.Shared)
{
}
public new JsonSerializerSettings SerializerSettings => base.SerializerSettings;
}
private sealed class User private sealed class User
{ {
public string Name { get; set; } public string Name { get; set; }

View File

@ -2,28 +2,34 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Buffers;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.JsonPatch; using Microsoft.AspNetCore.JsonPatch;
using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Logging.Testing;
using Microsoft.Extensions.ObjectPool;
using Moq; using Moq;
using Newtonsoft.Json;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Mvc.Formatters namespace Microsoft.AspNetCore.Mvc.Formatters
{ {
public class JsonPatchInputFormatterTest public class JsonPatchInputFormatterTest
{ {
private static readonly ObjectPoolProvider _objectPoolProvider = new DefaultObjectPoolProvider();
private static readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings();
[Fact] [Fact]
public async Task JsonPatchInputFormatter_ReadsOneOperation_Successfully() public async Task JsonPatchInputFormatter_ReadsOneOperation_Successfully()
{ {
// Arrange // Arrange
var logger = GetLogger(); var logger = GetLogger();
var formatter = new JsonPatchInputFormatter(logger); var formatter =
new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
var content = "[{\"op\":\"add\",\"path\":\"Customer/Name\",\"value\":\"John\"}]"; var content = "[{\"op\":\"add\",\"path\":\"Customer/Name\",\"value\":\"John\"}]";
var contentBytes = Encoding.UTF8.GetBytes(content); var contentBytes = Encoding.UTF8.GetBytes(content);
@ -54,7 +60,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
{ {
// Arrange // Arrange
var logger = GetLogger(); var logger = GetLogger();
var formatter = new JsonPatchInputFormatter(logger); var formatter =
new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
var content = "[{\"op\": \"add\", \"path\" : \"Customer/Name\", \"value\":\"John\"}," + var content = "[{\"op\": \"add\", \"path\" : \"Customer/Name\", \"value\":\"John\"}," +
"{\"op\": \"remove\", \"path\" : \"Customer/Name\"}]"; "{\"op\": \"remove\", \"path\" : \"Customer/Name\"}]";
var contentBytes = Encoding.UTF8.GetBytes(content); var contentBytes = Encoding.UTF8.GetBytes(content);
@ -92,7 +99,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
{ {
// Arrange // Arrange
var logger = GetLogger(); var logger = GetLogger();
var formatter = new JsonPatchInputFormatter(logger); var formatter =
new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
var content = "[{\"op\": \"add\", \"path\" : \"Customer/Name\", \"value\":\"John\"}]"; var content = "[{\"op\": \"add\", \"path\" : \"Customer/Name\", \"value\":\"John\"}]";
var contentBytes = Encoding.UTF8.GetBytes(content); var contentBytes = Encoding.UTF8.GetBytes(content);
@ -121,7 +129,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
{ {
// Arrange // Arrange
var logger = GetLogger(); var logger = GetLogger();
var formatter = new JsonPatchInputFormatter(logger); var formatter =
new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
var content = "[{\"op\": \"add\", \"path\" : \"Customer/Name\", \"value\":\"John\"}]"; var content = "[{\"op\": \"add\", \"path\" : \"Customer/Name\", \"value\":\"John\"}]";
var contentBytes = Encoding.UTF8.GetBytes(content); 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 "; $"'{typeof(Customer).FullName}' because the type requires a JSON object ";
var logger = GetLogger(); var logger = GetLogger();
var formatter = new JsonPatchInputFormatter(logger); var formatter =
new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
var content = "[{\"op\": \"add\", \"path\" : \"Customer/Name\", \"value\":\"John\"}]"; var content = "[{\"op\": \"add\", \"path\" : \"Customer/Name\", \"value\":\"John\"}]";
var contentBytes = Encoding.UTF8.GetBytes(content); var contentBytes = Encoding.UTF8.GetBytes(content);

View File

@ -7,7 +7,6 @@ using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Reflection; using System.Reflection;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Serialization;
@ -248,11 +247,13 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
public async Task JsonHelperWithSettings_RendersJson() public async Task JsonHelperWithSettings_RendersJson()
{ {
// Arrange // Arrange
var json = JsonConvert.SerializeObject(new BasicWebSite.Models.Person() var json = JsonConvert.SerializeObject(
{ new BasicWebSite.Models.Person()
Id = 9000, {
Name = "John <b>Smith</b>" Id = 9000,
}, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }); Name = "John <b>Smith</b>"
},
new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() });
var expectedBody = string.Format( var expectedBody = string.Format(
@"<script type=""text/javascript""> @"<script type=""text/javascript"">

View File

@ -4,8 +4,8 @@
using System.Buffers; using System.Buffers;
using Microsoft.AspNetCore.Mvc.DataAnnotations; using Microsoft.AspNetCore.Mvc.DataAnnotations;
using Microsoft.AspNetCore.Mvc.DataAnnotations.Internal; using Microsoft.AspNetCore.Mvc.DataAnnotations.Internal;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc.Formatters.Json.Internal; using Microsoft.AspNetCore.Mvc.Formatters.Json.Internal;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Internal; using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
collection.BuildServiceProvider()); collection.BuildServiceProvider());
var loggerFactory = new LoggerFactory(); var loggerFactory = new LoggerFactory();
var serializerSettings = SerializerSettingsProvider.CreateSerializerSettings(); var serializerSettings = JsonSerializerSettingsProvider.CreateSerializerSettings();
MvcJsonMvcOptionsSetup.ConfigureMvc( MvcJsonMvcOptionsSetup.ConfigureMvc(
Value, Value,

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Buffers;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -19,6 +20,7 @@ using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.WebEncoders.Testing; using Microsoft.Extensions.WebEncoders.Testing;
using Moq; using Moq;
using Newtonsoft.Json;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor namespace Microsoft.AspNetCore.Mvc.Razor
@ -32,7 +34,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor
var modelMetadataProvider = new EmptyModelMetadataProvider(); var modelMetadataProvider = new EmptyModelMetadataProvider();
var modelExpressionProvider = new ModelExpressionProvider(modelMetadataProvider, new ExpressionTextCache()); var modelExpressionProvider = new ModelExpressionProvider(modelMetadataProvider, new ExpressionTextCache());
var urlHelperFactory = new UrlHelperFactory(); var urlHelperFactory = new UrlHelperFactory();
var jsonHelper = new JsonHelper(new JsonOutputFormatter()); var jsonHelper = new JsonHelper(
new JsonOutputFormatter(new JsonSerializerSettings(), ArrayPool<char>.Shared),
ArrayPool<char>.Shared);
var htmlEncoder = new HtmlTestEncoder(); var htmlEncoder = new HtmlTestEncoder();
var diagnosticSource = new DiagnosticListener("Microsoft.AspNetCore"); var diagnosticSource = new DiagnosticListener("Microsoft.AspNetCore");
var activator = new RazorPageActivator( var activator = new RazorPageActivator(
@ -92,7 +96,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor
var activator = new RazorPageActivator( var activator = new RazorPageActivator(
modelMetadataProvider, modelMetadataProvider,
new UrlHelperFactory(), new UrlHelperFactory(),
new JsonHelper(new JsonOutputFormatter()), new JsonHelper(
new JsonOutputFormatter(new JsonSerializerSettings(), ArrayPool<char>.Shared),
ArrayPool<char>.Shared),
new DiagnosticListener("Microsoft.AspNetCore"), new DiagnosticListener("Microsoft.AspNetCore"),
new HtmlTestEncoder(), new HtmlTestEncoder(),
modelExpressionProvider); modelExpressionProvider);
@ -131,7 +137,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor
var activator = new RazorPageActivator( var activator = new RazorPageActivator(
modelMetadataProvider, modelMetadataProvider,
new UrlHelperFactory(), new UrlHelperFactory(),
new JsonHelper(new JsonOutputFormatter()), new JsonHelper(
new JsonOutputFormatter(new JsonSerializerSettings(), ArrayPool<char>.Shared),
ArrayPool<char>.Shared),
new DiagnosticListener("Microsoft.AspNetCore.Mvc"), new DiagnosticListener("Microsoft.AspNetCore.Mvc"),
new HtmlTestEncoder(), new HtmlTestEncoder(),
modelExpressionProvider); modelExpressionProvider);
@ -179,7 +187,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor
var activator = new RazorPageActivator( var activator = new RazorPageActivator(
modelMetadataProvider, modelMetadataProvider,
new UrlHelperFactory(), new UrlHelperFactory(),
new JsonHelper(new JsonOutputFormatter()), new JsonHelper(
new JsonOutputFormatter(new JsonSerializerSettings(), ArrayPool<char>.Shared),
ArrayPool<char>.Shared),
new DiagnosticListener("Microsoft.AspNetCore.Mvc"), new DiagnosticListener("Microsoft.AspNetCore.Mvc"),
new HtmlTestEncoder(), new HtmlTestEncoder(),
modelExpressionProvider); modelExpressionProvider);
@ -226,7 +236,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor
var activator = new RazorPageActivator( var activator = new RazorPageActivator(
modelMetadataProvider, modelMetadataProvider,
new UrlHelperFactory(), new UrlHelperFactory(),
new JsonHelper(new JsonOutputFormatter()), new JsonHelper(
new JsonOutputFormatter(new JsonSerializerSettings(), ArrayPool<char>.Shared),
ArrayPool<char>.Shared),
new DiagnosticListener("Microsoft.AspNetCore.Mvc"), new DiagnosticListener("Microsoft.AspNetCore.Mvc"),
new HtmlTestEncoder(), new HtmlTestEncoder(),
modelExpressionProvider); modelExpressionProvider);
@ -270,7 +282,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor
var activator = new RazorPageActivator( var activator = new RazorPageActivator(
modelMetadataProvider, modelMetadataProvider,
new UrlHelperFactory(), new UrlHelperFactory(),
new JsonHelper(new JsonOutputFormatter()), new JsonHelper(
new JsonOutputFormatter(new JsonSerializerSettings(), ArrayPool<char>.Shared),
ArrayPool<char>.Shared),
new DiagnosticListener("Microsoft.AspNetCore.Mvc"), new DiagnosticListener("Microsoft.AspNetCore.Mvc"),
new HtmlTestEncoder(), new HtmlTestEncoder(),
modelExpressionProvider); modelExpressionProvider);
@ -306,7 +320,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor
var activator = new RazorPageActivator( var activator = new RazorPageActivator(
modelMetadataProvider, modelMetadataProvider,
new UrlHelperFactory(), new UrlHelperFactory(),
new JsonHelper(new JsonOutputFormatter()), new JsonHelper(
new JsonOutputFormatter(new JsonSerializerSettings(), ArrayPool<char>.Shared),
ArrayPool<char>.Shared),
new DiagnosticListener("Microsoft.AspNetCore.Mvc"), new DiagnosticListener("Microsoft.AspNetCore.Mvc"),
new HtmlTestEncoder(), new HtmlTestEncoder(),
modelExpressionProvider); modelExpressionProvider);

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
@ -10,7 +11,7 @@ using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc.Internal; using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor.Internal; using Microsoft.AspNetCore.Mvc.Razor.Internal;
@ -23,6 +24,7 @@ using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.WebEncoders.Testing; using Microsoft.Extensions.WebEncoders.Testing;
using Moq; using Moq;
using Newtonsoft.Json;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor namespace Microsoft.AspNetCore.Mvc.Razor
@ -75,7 +77,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor
var activator = new RazorPageActivator( var activator = new RazorPageActivator(
modelMetadataProvider, modelMetadataProvider,
new UrlHelperFactory(), new UrlHelperFactory(),
new JsonHelper(new Formatters.JsonOutputFormatter()), new JsonHelper(
new JsonOutputFormatter(new JsonSerializerSettings(), ArrayPool<char>.Shared),
ArrayPool<char>.Shared),
new DiagnosticListener("Microsoft.AspNetCore"), new DiagnosticListener("Microsoft.AspNetCore"),
new HtmlTestEncoder(), new HtmlTestEncoder(),
modelExpressionProvider); modelExpressionProvider);

View File

@ -204,33 +204,6 @@ namespace Microsoft.AspNetCore.Mvc
}); });
} }
[Fact]
public void Setup_JsonFormattersUseSerializerSettings()
{
// Arrange
var services = GetServiceProvider(s =>
{
s.AddTransient<ILoggerFactory, LoggerFactory>();
});
// Act
var options = services.GetRequiredService<IOptions<MvcOptions>>().Value;
var jsonOptions = services.GetRequiredService<IOptions<MvcJsonOptions>>().Value;
// Assert
var jsonInputFormatters = options.InputFormatters.OfType<JsonInputFormatter>();
foreach (var jsonInputFormatter in jsonInputFormatters)
{
Assert.Same(jsonOptions.SerializerSettings, jsonInputFormatter.SerializerSettings);
}
var jsonOuputFormatters = options.OutputFormatters.OfType<JsonOutputFormatter>();
foreach (var jsonOuputFormatter in jsonOuputFormatters)
{
Assert.Same(jsonOptions.SerializerSettings, jsonOuputFormatter.SerializerSettings);
}
}
private static T GetOptions<T>(Action<IServiceCollection> action = null) private static T GetOptions<T>(Action<IServiceCollection> action = null)
where T : class, new() where T : class, new()
{ {

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Buffers;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
@ -12,6 +13,7 @@ using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Logging.Testing;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Xunit; using Xunit;
namespace System.Web.Http namespace System.Web.Http
@ -67,7 +69,9 @@ namespace System.Web.Http
{ {
var options = new OptionsManager<MvcOptions>(new IConfigureOptions<MvcOptions>[] { }); var options = new OptionsManager<MvcOptions>(new IConfigureOptions<MvcOptions>[] { });
options.Value.OutputFormatters.Add(new StringOutputFormatter()); options.Value.OutputFormatters.Add(new StringOutputFormatter());
options.Value.OutputFormatters.Add(new JsonOutputFormatter()); options.Value.OutputFormatters.Add(new JsonOutputFormatter(
new JsonSerializerSettings(),
ArrayPool<char>.Shared));
var services = new ServiceCollection(); var services = new ServiceCollection();
services.AddSingleton(new ObjectResultExecutor( services.AddSingleton(new ObjectResultExecutor(

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Buffers;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
@ -12,6 +13,7 @@ using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Logging.Testing;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Xunit; using Xunit;
namespace System.Web.Http namespace System.Web.Http
@ -67,7 +69,9 @@ namespace System.Web.Http
{ {
var options = new OptionsManager<MvcOptions>(new IConfigureOptions<MvcOptions>[] { }); var options = new OptionsManager<MvcOptions>(new IConfigureOptions<MvcOptions>[] { });
options.Value.OutputFormatters.Add(new StringOutputFormatter()); options.Value.OutputFormatters.Add(new StringOutputFormatter());
options.Value.OutputFormatters.Add(new JsonOutputFormatter()); options.Value.OutputFormatters.Add(new JsonOutputFormatter(
new JsonSerializerSettings(),
ArrayPool<char>.Shared));
var services = new ServiceCollection(); var services = new ServiceCollection();
services.AddSingleton(new ObjectResultExecutor( services.AddSingleton(new ObjectResultExecutor(

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Buffers;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
@ -13,6 +14,7 @@ using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Logging.Testing;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Xunit; using Xunit;
namespace System.Web.Http namespace System.Web.Http
@ -80,7 +82,9 @@ namespace System.Web.Http
{ {
var options = new OptionsManager<MvcOptions>(new IConfigureOptions<MvcOptions>[] { }); var options = new OptionsManager<MvcOptions>(new IConfigureOptions<MvcOptions>[] { });
options.Value.OutputFormatters.Add(new StringOutputFormatter()); options.Value.OutputFormatters.Add(new StringOutputFormatter());
options.Value.OutputFormatters.Add(new JsonOutputFormatter()); options.Value.OutputFormatters.Add(new JsonOutputFormatter(
new JsonSerializerSettings(),
ArrayPool<char>.Shared));
var services = new ServiceCollection(); var services = new ServiceCollection();
services.AddSingleton(new ObjectResultExecutor( services.AddSingleton(new ObjectResultExecutor(

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Buffers;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -13,6 +14,7 @@ using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Logging.Testing;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Xunit; using Xunit;
namespace System.Web.Http namespace System.Web.Http
@ -68,7 +70,9 @@ namespace System.Web.Http
{ {
var options = new OptionsManager<MvcOptions>(new IConfigureOptions<MvcOptions>[] { }); var options = new OptionsManager<MvcOptions>(new IConfigureOptions<MvcOptions>[] { });
options.Value.OutputFormatters.Add(new StringOutputFormatter()); options.Value.OutputFormatters.Add(new StringOutputFormatter());
options.Value.OutputFormatters.Add(new JsonOutputFormatter()); options.Value.OutputFormatters.Add(new JsonOutputFormatter(
new JsonSerializerSettings(),
ArrayPool<char>.Shared));
var services = new ServiceCollection(); var services = new ServiceCollection();
services.AddSingleton(new ObjectResultExecutor( services.AddSingleton(new ObjectResultExecutor(

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO; using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.AspNetCore.Mvc.Formatters;
@ -24,8 +25,10 @@ namespace ApiExplorerWebSite
options.Conventions.Add(new ApiExplorerVisibilityDisabledConvention( options.Conventions.Add(new ApiExplorerVisibilityDisabledConvention(
typeof(ApiExplorerVisbilityDisabledByConventionController))); typeof(ApiExplorerVisbilityDisabledByConventionController)));
var jsonOutputFormatter = options.OutputFormatters.OfType<JsonOutputFormatter>().First();
options.OutputFormatters.Clear(); options.OutputFormatters.Clear();
options.OutputFormatters.Add(new JsonOutputFormatter()); options.OutputFormatters.Add(jsonOutputFormatter);
options.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); options.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
}); });

View File

@ -1,16 +1,25 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using BasicWebSite.Formatters; using BasicWebSite.Formatters;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
namespace BasicWebSite.Controllers.ContentNegotiation namespace BasicWebSite.Controllers.ContentNegotiation
{ {
public class FallbackOnTypeBasedMatchController : Controller public class FallbackOnTypeBasedMatchController : Controller
{ {
private readonly IOptions<MvcOptions> _mvcOptions;
private readonly JsonOutputFormatter _jsonOutputFormatter;
public FallbackOnTypeBasedMatchController(IOptions<MvcOptions> mvcOptions)
{
_mvcOptions = mvcOptions;
_jsonOutputFormatter = mvcOptions.Value.OutputFormatters.OfType<JsonOutputFormatter>().First();
}
public int UseTheFallback_WithDefaultFormatters(int input) public int UseTheFallback_WithDefaultFormatters(int input)
{ {
return input; return input;
@ -25,7 +34,7 @@ namespace BasicWebSite.Controllers.ContentNegotiation
// JsonOutputFormatter cannot write in the first attempt because it does not support the // JsonOutputFormatter cannot write in the first attempt because it does not support the
// request content type. // request content type.
objectResult.Formatters.Add(new PlainTextFormatter()); objectResult.Formatters.Add(new PlainTextFormatter());
objectResult.Formatters.Add(new JsonOutputFormatter()); objectResult.Formatters.Add(_jsonOutputFormatter);
return objectResult; return objectResult;
} }
@ -46,17 +55,16 @@ namespace BasicWebSite.Controllers.ContentNegotiation
var objectResult = new ObjectResult(input); var objectResult = new ObjectResult(input);
objectResult.Formatters.Add(new HttpNotAcceptableOutputFormatter()); objectResult.Formatters.Add(new HttpNotAcceptableOutputFormatter());
objectResult.Formatters.Add(new PlainTextFormatter()); objectResult.Formatters.Add(new PlainTextFormatter());
objectResult.Formatters.Add(new JsonOutputFormatter()); objectResult.Formatters.Add(_jsonOutputFormatter);
return objectResult; return objectResult;
} }
public IActionResult OverrideTheFallback_WithDefaultFormatters(int input) public IActionResult OverrideTheFallback_WithDefaultFormatters(int input)
{ {
var objectResult = new ObjectResult(input); var objectResult = new ObjectResult(input);
var optionsAccessor = HttpContext.RequestServices
.GetRequiredService<IOptions<MvcOptions>>();
objectResult.Formatters.Add(new HttpNotAcceptableOutputFormatter()); objectResult.Formatters.Add(new HttpNotAcceptableOutputFormatter());
foreach (var formatter in optionsAccessor.Value.OutputFormatters) foreach (var formatter in _mvcOptions.Value.OutputFormatters)
{ {
objectResult.Formatters.Add(formatter); objectResult.Formatters.Add(formatter);
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Buffers;
using BasicWebSite.Formatters; using BasicWebSite.Formatters;
using BasicWebSite.Models; using BasicWebSite.Models;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -12,6 +13,20 @@ namespace BasicWebSite.Controllers.ContentNegotiation
{ {
public class NormalController : Controller public class NormalController : Controller
{ {
private static readonly JsonSerializerSettings _indentedSettings;
private readonly JsonOutputFormatter _indentingFormatter;
static NormalController()
{
_indentedSettings = JsonSerializerSettingsProvider.CreateSerializerSettings();
_indentedSettings.Formatting = Formatting.Indented;
}
public NormalController(ArrayPool<char> charPool)
{
_indentingFormatter = new JsonOutputFormatter(_indentedSettings, charPool);
}
public override void OnActionExecuted(ActionExecutedContext context) public override void OnActionExecuted(ActionExecutedContext context)
{ {
var result = context.Result as ObjectResult; var result = context.Result as ObjectResult;
@ -19,10 +34,7 @@ namespace BasicWebSite.Controllers.ContentNegotiation
{ {
result.Formatters.Add(new PlainTextFormatter()); result.Formatters.Add(new PlainTextFormatter());
result.Formatters.Add(new CustomFormatter("application/custom")); result.Formatters.Add(new CustomFormatter("application/custom"));
result.Formatters.Add(_indentingFormatter);
var jsonFormatter = new JsonOutputFormatter();
jsonFormatter.SerializerSettings.Formatting = Formatting.Indented;
result.Formatters.Add(jsonFormatter);
} }
base.OnActionExecuted(context); base.OnActionExecuted(context);

View File

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Net.Http.Headers; using Microsoft.AspNetCore.Mvc.Formatters;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Serialization;
@ -10,7 +10,13 @@ namespace BasicWebSite.Controllers
{ {
public class JsonResultController : Controller public class JsonResultController : Controller
{ {
private static JsonSerializerSettings _customSerializerSettings; private static readonly JsonSerializerSettings _customSerializerSettings;
static JsonResultController()
{
_customSerializerSettings = JsonSerializerSettingsProvider.CreateSerializerSettings();
_customSerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
public JsonResult Plain() public JsonResult Plain()
{ {
@ -26,14 +32,6 @@ namespace BasicWebSite.Controllers
public JsonResult CustomSerializerSettings() public JsonResult CustomSerializerSettings()
{ {
if (_customSerializerSettings == null)
{
_customSerializerSettings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
}
return Json(new { Message = "hello" }, _customSerializerSettings); return Json(new { Message = "hello" }, _customSerializerSettings);
} }

View File

@ -1,5 +1,10 @@
@using Newtonsoft.Json @using Microsoft.AspNetCore.Mvc.Formatters
@using Newtonsoft.Json
@using Newtonsoft.Json.Serialization @using Newtonsoft.Json.Serialization
@{
var settings = JsonSerializerSettingsProvider.CreateSerializerSettings();
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
<script type="text/javascript"> <script type="text/javascript">
var json = @Json.Serialize(Model, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }); var json = @Json.Serialize(Model, settings);
</script> </script>

View File

@ -2,9 +2,12 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Linq;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
namespace FiltersWebSite.Controllers namespace FiltersWebSite.Controllers
{ {
@ -27,24 +30,16 @@ namespace FiltersWebSite.Controllers
private class ShortCircuitWithFormatterAttribute : Attribute, IResourceFilter private class ShortCircuitWithFormatterAttribute : Attribute, IResourceFilter
{ {
private IOutputFormatter[] _formatters;
public ShortCircuitWithFormatterAttribute()
{
_formatters = new IOutputFormatter[] { new JsonOutputFormatter() };
}
public void OnResourceExecuted(ResourceExecutedContext context) public void OnResourceExecuted(ResourceExecutedContext context)
{ {
} }
public void OnResourceExecuting(ResourceExecutingContext context) public void OnResourceExecuting(ResourceExecutingContext context)
{ {
var mvcOptions = context.HttpContext.RequestServices.GetRequiredService<IOptions<MvcOptions>>();
var formatter = mvcOptions.Value.OutputFormatters.OfType<JsonOutputFormatter>().First();
var result = new ObjectResult("someValue"); var result = new ObjectResult("someValue");
foreach (var formatter in _formatters) result.Formatters.Add(formatter);
{
result.Formatters.Add(formatter);
}
context.Result = result; context.Result = result;
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // 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.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.AspNetCore.Mvc.Formatters;
@ -10,6 +11,20 @@ namespace FormatterWebSite.Controllers
{ {
public class JsonFormatterController : Controller 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<char> charPool)
{
_indentingFormatter = new JsonOutputFormatter(_indentedSettings, charPool);
}
public IActionResult ReturnsIndentedJson() public IActionResult ReturnsIndentedJson()
{ {
var user = new User() var user = new User()
@ -21,11 +36,8 @@ namespace FormatterWebSite.Controllers
Name = "John Williams" Name = "John Williams"
}; };
var jsonFormatter = new JsonOutputFormatter();
jsonFormatter.SerializerSettings.Formatting = Formatting.Indented;
var objectResult = new ObjectResult(user); var objectResult = new ObjectResult(user);
objectResult.Formatters.Add(jsonFormatter); objectResult.Formatters.Add(_indentingFormatter);
return objectResult; return objectResult;
} }

View File

@ -7,12 +7,21 @@ using System.Net.Http;
using System.Text; using System.Text;
using System.Web.Http; using System.Web.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace WebApiCompatShimWebSite namespace WebApiCompatShimWebSite
{ {
public class ActionResultController : ApiController public class ActionResultController : ApiController
{ {
private static readonly JsonSerializerSettings _indentedSettings;
static ActionResultController()
{
_indentedSettings = JsonSerializerSettingsProvider.CreateSerializerSettings();
_indentedSettings.Formatting = Formatting.Indented;
}
public IActionResult GetBadRequest() public IActionResult GetBadRequest()
{ {
return BadRequest(); return BadRequest();
@ -82,15 +91,12 @@ namespace WebApiCompatShimWebSite
public IActionResult GetJsonSettings() public IActionResult GetJsonSettings()
{ {
return Json(CreateUser(), new JsonSerializerSettings() { Formatting = Formatting.Indented }); return Json(CreateUser(), _indentedSettings);
} }
public IActionResult GetJsonSettingsEncoding() public IActionResult GetJsonSettingsEncoding()
{ {
return Json( return Json(CreateUser(), _indentedSettings, Encoding.UTF32);
CreateUser(),
new JsonSerializerSettings() { Formatting = Formatting.Indented },
Encoding.UTF32);
} }
public IActionResult GetNotFound() public IActionResult GetNotFound()