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
{
/// <summary>
/// An <see cref="TextInputFormatter"/> for JSON content.
/// A <see cref="TextInputFormatter"/> for JSON content.
/// </summary>
public class JsonInputFormatter : TextInputFormatter
{
@ -22,36 +22,16 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
private readonly ILogger _logger;
private readonly ObjectPoolProvider _objectPoolProvider;
private ObjectPool<JsonSerializer> _jsonSerializerPool;
private JsonSerializerSettings _serializerSettings;
/// <summary>
/// Initializes a new instance of <see cref="JsonInputFormatter"/>.
/// </summary>
/// <param name="logger">The <see cref="ILogger"/>.</param>
public JsonInputFormatter(ILogger logger)
: this(logger, SerializerSettingsProvider.CreateSerializerSettings())
{
}
/// <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="serializerSettings">
/// 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 JsonInputFormatter(
@ -81,7 +61,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
}
_logger = logger;
_serializerSettings = serializerSettings;
SerializerSettings = serializerSettings;
_charPool = new JsonArrayPool<char>(charPool);
_objectPoolProvider = objectPoolProvider;
@ -93,28 +73,13 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
}
/// <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>
/// <remarks>
/// Any modifications to the <see cref="JsonSerializerSettings"/> object after this
/// <see cref="JsonInputFormatter"/> has been used will have no effect.
/// </remarks>
public JsonSerializerSettings SerializerSettings
{
get
{
return _serializerSettings;
}
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
_serializerSettings = value;
}
}
protected JsonSerializerSettings SerializerSettings { get; }
/// <inheritdoc />
public override Task<InputFormatterResult> ReadRequestBodyAsync(

View File

@ -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
{
/// <summary>
/// An output formatter that specializes in writing JSON content.
/// A <see cref="TextOutputFormatter"/> for JSON content.
/// </summary>
public class JsonOutputFormatter : TextOutputFormatter
{
private readonly IArrayPool<char> _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<char>.Shared)
{
}
public JsonOutputFormatter(JsonSerializerSettings serializerSettings)
: this(serializerSettings, ArrayPool<char>.Shared)
{
}
/// <summary>
/// Initializes a new <see cref="JsonOutputFormatter"/> instance.
/// </summary>
/// <param name="serializerSettings">
/// 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>
public JsonOutputFormatter(JsonSerializerSettings serializerSettings, ArrayPool<char> 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<char>(charPool);
SupportedEncodings.Add(Encoding.UTF8);
@ -57,31 +53,13 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
}
/// <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>
/// <remarks>
/// Any modifications to the <see cref="JsonSerializerSettings"/> object after this
/// <see cref="JsonOutputFormatter"/> has been used will have no effect.
/// </remarks>
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; }
/// <summary>
/// Writes the given <paramref name="value"/> 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();
}

View File

@ -14,17 +14,21 @@ using Newtonsoft.Json;
namespace Microsoft.AspNetCore.Mvc.Formatters
{
/// <summary>
/// A <see cref="TextInputFormatter"/> for JSON Patch (application/json-patch+json) content.
/// </summary>
public class JsonPatchInputFormatter : JsonInputFormatter
{
public JsonPatchInputFormatter(ILogger logger)
: this(
logger,
SerializerSettingsProvider.CreateSerializerSettings(),
ArrayPool<char>.Shared,
new DefaultObjectPoolProvider())
{
}
/// <summary>
/// Initializes a new <see cref="JsonPatchInputFormatter"/> instance.
/// </summary>
/// <param name="logger">The <see cref="ILogger"/>.</param>
/// <param name="serializerSettings">
/// 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(
ILogger logger,
JsonSerializerSettings serializerSettings,

View File

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

View File

@ -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
/// <summary>
/// Gets the <see cref="JsonSerializerSettings"/> that are used by this application.
/// </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.
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<char> _charPool;
/// <summary>
/// Initializes a new instance of <see cref="JsonHelper"/> that is backed by <paramref name="jsonOutputFormatter"/>.
/// </summary>
/// <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)
{
throw new ArgumentNullException(nameof(jsonOutputFormatter));
}
if (charPool == null)
{
throw new ArgumentNullException(nameof(charPool));
}
_jsonOutputFormatter = jsonOutputFormatter;
_charPool = charPool;
}
/// <inheritdoc />
@ -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);
}

View File

@ -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<MvcOptions>();
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();
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.
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<MvcOptions>();
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();
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.
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<MvcOptions>();
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();
services.AddSingleton(new ObjectResultExecutor(

View File

@ -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<char>.Shared));
// Set up default mapping for json extensions to content type
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.
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<MvcOptions>();
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();
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.
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<MvcOptions>();
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();
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.
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<char>.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<char>.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<char>.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<char>.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<char>.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<char>.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<char>.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<char>.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<char>.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<char>.Shared, _objectPoolProvider);
var contentBytes = Encoding.UTF8.GetBytes(content);
var modelState = new ModelStateDictionary();
@ -322,66 +337,19 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
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]
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<char>.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<char>.Shared, _objectPoolProvider)
{
}
public new JsonSerializerSettings SerializerSettings => base.SerializerSettings;
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.
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<char>.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<char>.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<char>.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<char>.Shared)
{
}
public new JsonSerializerSettings SerializerSettings => base.SerializerSettings;
}
private sealed class User
{
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.
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<char>.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<char>.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<char>.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<char>.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<char>.Shared, _objectPoolProvider);
var content = "[{\"op\": \"add\", \"path\" : \"Customer/Name\", \"value\":\"John\"}]";
var contentBytes = Encoding.UTF8.GetBytes(content);

View File

@ -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 <b>Smith</b>"
}, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() });
var json = JsonConvert.SerializeObject(
new BasicWebSite.Models.Person()
{
Id = 9000,
Name = "John <b>Smith</b>"
},
new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() });
var expectedBody = string.Format(
@"<script type=""text/javascript"">

View File

@ -4,8 +4,8 @@
using System.Buffers;
using Microsoft.AspNetCore.Mvc.DataAnnotations;
using Microsoft.AspNetCore.Mvc.DataAnnotations.Internal;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc.Formatters.Json.Internal;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
collection.BuildServiceProvider());
var loggerFactory = new LoggerFactory();
var serializerSettings = SerializerSettingsProvider.CreateSerializerSettings();
var serializerSettings = JsonSerializerSettingsProvider.CreateSerializerSettings();
MvcJsonMvcOptionsSetup.ConfigureMvc(
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.
using System;
using System.Buffers;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
@ -19,6 +20,7 @@ using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.WebEncoders.Testing;
using Moq;
using Newtonsoft.Json;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor
@ -32,7 +34,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor
var modelMetadataProvider = new EmptyModelMetadataProvider();
var modelExpressionProvider = new ModelExpressionProvider(modelMetadataProvider, new ExpressionTextCache());
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 diagnosticSource = new DiagnosticListener("Microsoft.AspNetCore");
var activator = new RazorPageActivator(
@ -47,7 +51,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
var myService = new MyService();
var helper = Mock.Of<IHtmlHelper<object>>();
var serviceProvider = new ServiceCollection()
.AddSingleton(myService)
.AddSingleton(helper)
@ -92,7 +96,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor
var activator = new RazorPageActivator(
modelMetadataProvider,
new UrlHelperFactory(),
new JsonHelper(new JsonOutputFormatter()),
new JsonHelper(
new JsonOutputFormatter(new JsonSerializerSettings(), ArrayPool<char>.Shared),
ArrayPool<char>.Shared),
new DiagnosticListener("Microsoft.AspNetCore"),
new HtmlTestEncoder(),
modelExpressionProvider);
@ -131,7 +137,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor
var activator = new RazorPageActivator(
modelMetadataProvider,
new UrlHelperFactory(),
new JsonHelper(new JsonOutputFormatter()),
new JsonHelper(
new JsonOutputFormatter(new JsonSerializerSettings(), ArrayPool<char>.Shared),
ArrayPool<char>.Shared),
new DiagnosticListener("Microsoft.AspNetCore.Mvc"),
new HtmlTestEncoder(),
modelExpressionProvider);
@ -179,7 +187,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor
var activator = new RazorPageActivator(
modelMetadataProvider,
new UrlHelperFactory(),
new JsonHelper(new JsonOutputFormatter()),
new JsonHelper(
new JsonOutputFormatter(new JsonSerializerSettings(), ArrayPool<char>.Shared),
ArrayPool<char>.Shared),
new DiagnosticListener("Microsoft.AspNetCore.Mvc"),
new HtmlTestEncoder(),
modelExpressionProvider);
@ -226,7 +236,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor
var activator = new RazorPageActivator(
modelMetadataProvider,
new UrlHelperFactory(),
new JsonHelper(new JsonOutputFormatter()),
new JsonHelper(
new JsonOutputFormatter(new JsonSerializerSettings(), ArrayPool<char>.Shared),
ArrayPool<char>.Shared),
new DiagnosticListener("Microsoft.AspNetCore.Mvc"),
new HtmlTestEncoder(),
modelExpressionProvider);
@ -270,7 +282,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor
var activator = new RazorPageActivator(
modelMetadataProvider,
new UrlHelperFactory(),
new JsonHelper(new JsonOutputFormatter()),
new JsonHelper(
new JsonOutputFormatter(new JsonSerializerSettings(), ArrayPool<char>.Shared),
ArrayPool<char>.Shared),
new DiagnosticListener("Microsoft.AspNetCore.Mvc"),
new HtmlTestEncoder(),
modelExpressionProvider);
@ -306,7 +320,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor
var activator = new RazorPageActivator(
modelMetadataProvider,
new UrlHelperFactory(),
new JsonHelper(new JsonOutputFormatter()),
new JsonHelper(
new JsonOutputFormatter(new JsonSerializerSettings(), ArrayPool<char>.Shared),
ArrayPool<char>.Shared),
new DiagnosticListener("Microsoft.AspNetCore.Mvc"),
new HtmlTestEncoder(),
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.
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@ -10,7 +11,7 @@ using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor.Internal;
@ -23,6 +24,7 @@ using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.WebEncoders.Testing;
using Moq;
using Newtonsoft.Json;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor
@ -75,7 +77,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor
var activator = new RazorPageActivator(
modelMetadataProvider,
new UrlHelperFactory(),
new JsonHelper(new Formatters.JsonOutputFormatter()),
new JsonHelper(
new JsonOutputFormatter(new JsonSerializerSettings(), ArrayPool<char>.Shared),
ArrayPool<char>.Shared),
new DiagnosticListener("Microsoft.AspNetCore"),
new HtmlTestEncoder(),
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)
where T : class, new()
{

View File

@ -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 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 Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Xunit;
namespace System.Web.Http
@ -67,7 +69,9 @@ namespace System.Web.Http
{
var options = new OptionsManager<MvcOptions>(new IConfigureOptions<MvcOptions>[] { });
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();
services.AddSingleton(new ObjectResultExecutor(

View File

@ -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 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 Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Xunit;
namespace System.Web.Http
@ -67,7 +69,9 @@ namespace System.Web.Http
{
var options = new OptionsManager<MvcOptions>(new IConfigureOptions<MvcOptions>[] { });
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();
services.AddSingleton(new ObjectResultExecutor(

View File

@ -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 System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
@ -13,6 +14,7 @@ using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Testing;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Xunit;
namespace System.Web.Http
@ -80,7 +82,9 @@ namespace System.Web.Http
{
var options = new OptionsManager<MvcOptions>(new IConfigureOptions<MvcOptions>[] { });
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();
services.AddSingleton(new ObjectResultExecutor(

View File

@ -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 System.IO;
using System.Net;
using System.Threading.Tasks;
@ -13,6 +14,7 @@ using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Testing;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Xunit;
namespace System.Web.Http
@ -68,7 +70,9 @@ namespace System.Web.Http
{
var options = new OptionsManager<MvcOptions>(new IConfigureOptions<MvcOptions>[] { });
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();
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.
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Formatters;
@ -24,8 +25,10 @@ namespace ApiExplorerWebSite
options.Conventions.Add(new ApiExplorerVisibilityDisabledConvention(
typeof(ApiExplorerVisbilityDisabledByConventionController)));
var jsonOutputFormatter = options.OutputFormatters.OfType<JsonOutputFormatter>().First();
options.OutputFormatters.Clear();
options.OutputFormatters.Add(new JsonOutputFormatter());
options.OutputFormatters.Add(jsonOutputFormatter);
options.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
});

View File

@ -1,16 +1,25 @@
// 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.Linq;
using BasicWebSite.Formatters;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
namespace BasicWebSite.Controllers.ContentNegotiation
{
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)
{
return input;
@ -25,7 +34,7 @@ namespace BasicWebSite.Controllers.ContentNegotiation
// JsonOutputFormatter cannot write in the first attempt because it does not support the
// request content type.
objectResult.Formatters.Add(new PlainTextFormatter());
objectResult.Formatters.Add(new JsonOutputFormatter());
objectResult.Formatters.Add(_jsonOutputFormatter);
return objectResult;
}
@ -46,17 +55,16 @@ namespace BasicWebSite.Controllers.ContentNegotiation
var objectResult = new ObjectResult(input);
objectResult.Formatters.Add(new HttpNotAcceptableOutputFormatter());
objectResult.Formatters.Add(new PlainTextFormatter());
objectResult.Formatters.Add(new JsonOutputFormatter());
objectResult.Formatters.Add(_jsonOutputFormatter);
return objectResult;
}
public IActionResult OverrideTheFallback_WithDefaultFormatters(int input)
{
var objectResult = new ObjectResult(input);
var optionsAccessor = HttpContext.RequestServices
.GetRequiredService<IOptions<MvcOptions>>();
objectResult.Formatters.Add(new HttpNotAcceptableOutputFormatter());
foreach (var formatter in optionsAccessor.Value.OutputFormatters)
foreach (var formatter in _mvcOptions.Value.OutputFormatters)
{
objectResult.Formatters.Add(formatter);
}

View File

@ -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 BasicWebSite.Formatters;
using BasicWebSite.Models;
using Microsoft.AspNetCore.Mvc;
@ -12,6 +13,20 @@ namespace BasicWebSite.Controllers.ContentNegotiation
{
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)
{
var result = context.Result as ObjectResult;
@ -19,10 +34,7 @@ namespace BasicWebSite.Controllers.ContentNegotiation
{
result.Formatters.Add(new PlainTextFormatter());
result.Formatters.Add(new CustomFormatter("application/custom"));
var jsonFormatter = new JsonOutputFormatter();
jsonFormatter.SerializerSettings.Formatting = Formatting.Indented;
result.Formatters.Add(jsonFormatter);
result.Formatters.Add(_indentingFormatter);
}
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.
using Microsoft.AspNetCore.Mvc;
using Microsoft.Net.Http.Headers;
using Microsoft.AspNetCore.Mvc.Formatters;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
@ -10,7 +10,13 @@ namespace BasicWebSite.Controllers
{
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()
{
@ -26,14 +32,6 @@ namespace BasicWebSite.Controllers
public JsonResult CustomSerializerSettings()
{
if (_customSerializerSettings == null)
{
_customSerializerSettings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
}
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
@{
var settings = JsonSerializerSettingsProvider.CreateSerializerSettings();
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
<script type="text/javascript">
var json = @Json.Serialize(Model, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() });
var json = @Json.Serialize(Model, settings);
</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.
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<IOptions<MvcOptions>>();
var formatter = mvcOptions.Value.OutputFormatters.OfType<JsonOutputFormatter>().First();
var result = new ObjectResult("someValue");
foreach (var formatter in _formatters)
{
result.Formatters.Add(formatter);
}
result.Formatters.Add(formatter);
context.Result = result;
}

View File

@ -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<char> 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;
}

View File

@ -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()