parent
fa8c2eac3e
commit
cf9221df07
|
|
@ -6,6 +6,7 @@ using Microsoft.AspNet.Mvc;
|
|||
using Microsoft.AspNet.Mvc.Formatters.Json.Internal;
|
||||
using Microsoft.AspNet.Mvc.Infrastructure;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
|
@ -54,6 +55,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, MvcJsonMvcOptionsSetup>());
|
||||
services.TryAddSingleton<JsonResultExecutor>();
|
||||
services.TryAddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
// 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.Extensions.ObjectPool;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Formatters.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="IPooledObjectPolicy{T}"/> for <see cref="JsonSerializer"/>.
|
||||
/// </summary>
|
||||
public class JsonSerializerObjectPolicy : IPooledObjectPolicy<JsonSerializer>
|
||||
{
|
||||
private readonly JsonSerializerSettings _serializerSettings;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="JsonSerializerObjectPolicy"/>.
|
||||
/// </summary>
|
||||
/// <param name="serializerSettings">The <see cref="JsonSerializerSettings"/> used to instantiate
|
||||
/// <see cref="JsonSerializer"/> instances.</param>
|
||||
public JsonSerializerObjectPolicy(JsonSerializerSettings serializerSettings)
|
||||
{
|
||||
_serializerSettings = serializerSettings;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public JsonSerializer Create() => JsonSerializer.Create(_serializerSettings);
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Return(JsonSerializer serializer) => true;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
using System.Buffers;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Newtonsoft.Json;
|
||||
|
|
@ -11,13 +12,29 @@ using Newtonsoft.Json.Linq;
|
|||
|
||||
namespace Microsoft.AspNet.Mvc.Formatters.Json.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets up JSON formatter options for <see cref="MvcOptions"/>.
|
||||
/// </summary>
|
||||
public class MvcJsonMvcOptionsSetup : ConfigureOptions<MvcOptions>
|
||||
{
|
||||
/// <summary>
|
||||
/// Intiailizes a new instance of <see cref="MvcJsonMvcOptionsSetup"/>.
|
||||
/// </summary>
|
||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||
/// <param name="jsonOptions"></param>
|
||||
/// <param name="charPool"></param>
|
||||
/// <param name="objectPoolProvider"></param>
|
||||
public MvcJsonMvcOptionsSetup(
|
||||
ILoggerFactory loggerFactory,
|
||||
IOptions<MvcJsonOptions> jsonOptions,
|
||||
ArrayPool<char> charPool)
|
||||
: base((options) => ConfigureMvc(options, jsonOptions.Value.SerializerSettings, loggerFactory, charPool))
|
||||
ArrayPool<char> charPool,
|
||||
ObjectPoolProvider objectPoolProvider)
|
||||
: base((options) => ConfigureMvc(
|
||||
options,
|
||||
jsonOptions.Value.SerializerSettings,
|
||||
loggerFactory,
|
||||
charPool,
|
||||
objectPoolProvider))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -25,15 +42,26 @@ namespace Microsoft.AspNet.Mvc.Formatters.Json.Internal
|
|||
MvcOptions options,
|
||||
JsonSerializerSettings serializerSettings,
|
||||
ILoggerFactory loggerFactory,
|
||||
ArrayPool<char> charPool)
|
||||
ArrayPool<char> charPool,
|
||||
ObjectPoolProvider objectPoolProvider)
|
||||
{
|
||||
var jsonInputLogger = loggerFactory.CreateLogger<JsonInputFormatter>();
|
||||
var jsonInputPatchLogger = loggerFactory.CreateLogger<JsonPatchInputFormatter>();
|
||||
|
||||
options.OutputFormatters.Add(new JsonOutputFormatter(serializerSettings, charPool));
|
||||
options.InputFormatters.Add(new JsonInputFormatter(jsonInputLogger, serializerSettings, charPool));
|
||||
options.InputFormatters.Add(new JsonPatchInputFormatter(jsonInputPatchLogger, serializerSettings, charPool));
|
||||
|
||||
|
||||
var jsonInputLogger = loggerFactory.CreateLogger<JsonInputFormatter>();
|
||||
options.InputFormatters.Add(new JsonInputFormatter(
|
||||
jsonInputLogger,
|
||||
serializerSettings,
|
||||
charPool,
|
||||
objectPoolProvider));
|
||||
|
||||
var jsonInputPatchLogger = loggerFactory.CreateLogger<JsonPatchInputFormatter>();
|
||||
options.InputFormatters.Add(new JsonPatchInputFormatter(
|
||||
jsonInputPatchLogger,
|
||||
serializerSettings,
|
||||
charPool,
|
||||
objectPoolProvider));
|
||||
|
||||
options.FormatterMappings.SetMediaTypeMappingForFormat("json", MediaTypeHeaderValue.Parse("application/json"));
|
||||
|
||||
options.ModelMetadataDetailsProviders.Add(new ValidationExcludeFilter(typeof(JToken)));
|
||||
|
|
|
|||
|
|
@ -4,47 +4,88 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.Formatters.Internal;
|
||||
using Microsoft.AspNet.Mvc.Formatters.Json.Internal;
|
||||
using Microsoft.AspNet.Mvc.Formatters.Json.Logging;
|
||||
using Microsoft.AspNet.Mvc.Internal;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Formatters
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="InputFormatter"/> for JSON content.
|
||||
/// </summary>
|
||||
public class JsonInputFormatter : InputFormatter
|
||||
{
|
||||
private readonly IArrayPool<char> _charPool;
|
||||
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(), ArrayPool<char>.Shared)
|
||||
: 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)
|
||||
: this(
|
||||
logger,
|
||||
serializerSettings,
|
||||
ArrayPool<char>.Shared,
|
||||
new DefaultObjectPoolProvider())
|
||||
{
|
||||
}
|
||||
|
||||
public JsonInputFormatter(ILogger logger, JsonSerializerSettings serializerSettings, ArrayPool<char> charPool)
|
||||
/// <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="objectPoolProvider">The <see cref="ObjectPoolProvider"/>.</param>
|
||||
public JsonInputFormatter(
|
||||
ILogger logger,
|
||||
JsonSerializerSettings serializerSettings,
|
||||
ArrayPool<char> charPool,
|
||||
ObjectPoolProvider objectPoolProvider)
|
||||
{
|
||||
if (serializerSettings == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(serializerSettings));
|
||||
}
|
||||
|
||||
if (logger == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
if (serializerSettings == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(serializerSettings));
|
||||
}
|
||||
|
||||
if (charPool == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(charPool));
|
||||
}
|
||||
|
||||
if (objectPoolProvider == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(objectPoolProvider));
|
||||
}
|
||||
|
||||
_logger = logger;
|
||||
_serializerSettings = serializerSettings;
|
||||
_charPool = new JsonArrayPool<char>(charPool);
|
||||
_objectPoolProvider = objectPoolProvider;
|
||||
|
||||
SupportedEncodings.Add(UTF8EncodingWithoutBOM);
|
||||
SupportedEncodings.Add(UTF16EncodingLittleEndian);
|
||||
|
|
@ -56,6 +97,10 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
|||
/// <summary>
|
||||
/// Gets or sets 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
|
||||
|
|
@ -135,7 +180,6 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
|||
var type = context.ModelType;
|
||||
var jsonSerializer = CreateJsonSerializer();
|
||||
jsonSerializer.Error += errorHandler;
|
||||
|
||||
object model;
|
||||
try
|
||||
{
|
||||
|
|
@ -143,8 +187,9 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
|||
}
|
||||
finally
|
||||
{
|
||||
// Clean up the error handler in case CreateJsonSerializer() reuses a serializer
|
||||
// Clean up the error handler since CreateJsonSerializer() pools instances.
|
||||
jsonSerializer.Error -= errorHandler;
|
||||
ReleaseJsonSerializer(jsonSerializer);
|
||||
}
|
||||
|
||||
if (successful)
|
||||
|
|
@ -160,12 +205,32 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
|||
/// <summary>
|
||||
/// Called during deserialization to get the <see cref="JsonSerializer"/>.
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="JsonSerializer"/> used during serialization and deserialization.</returns>
|
||||
/// <returns>The <see cref="JsonSerializer"/> used during deserialization.</returns>
|
||||
/// <remarks>
|
||||
/// This method works in tandem with <see cref="ReleaseJsonSerializer(JsonSerializer)"/> to
|
||||
/// manage the lifetimes of <see cref="JsonSerializer"/> instances.
|
||||
/// </remarks>
|
||||
protected virtual JsonSerializer CreateJsonSerializer()
|
||||
{
|
||||
return JsonSerializer.Create(SerializerSettings);
|
||||
if (_jsonSerializerPool == null)
|
||||
{
|
||||
_jsonSerializerPool = _objectPoolProvider.Create<JsonSerializer>();
|
||||
}
|
||||
|
||||
return _jsonSerializerPool.Get();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases the <paramref name="serializer"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="serializer">The <see cref="JsonSerializer"/> to release.</param>
|
||||
/// <remarks>
|
||||
/// This method works in tandem with <see cref="ReleaseJsonSerializer(JsonSerializer)"/> to
|
||||
/// manage the lifetimes of <see cref="JsonSerializer"/> instances.
|
||||
/// </remarks>
|
||||
protected virtual void ReleaseJsonSerializer(JsonSerializer serializer)
|
||||
=> _jsonSerializerPool.Return(serializer);
|
||||
|
||||
private ModelMetadata GetPathMetadata(ModelMetadata metadata, string path)
|
||||
{
|
||||
var index = 0;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNet.JsonPatch;
|
||||
using Microsoft.AspNet.Mvc.Internal;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Formatters
|
||||
|
|
@ -15,15 +16,20 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
|||
public class JsonPatchInputFormatter : JsonInputFormatter
|
||||
{
|
||||
public JsonPatchInputFormatter(ILogger logger)
|
||||
: this(logger, SerializerSettingsProvider.CreateSerializerSettings(), ArrayPool<char>.Shared)
|
||||
: this(
|
||||
logger,
|
||||
SerializerSettingsProvider.CreateSerializerSettings(),
|
||||
ArrayPool<char>.Shared,
|
||||
new DefaultObjectPoolProvider())
|
||||
{
|
||||
}
|
||||
|
||||
public JsonPatchInputFormatter(
|
||||
ILogger logger,
|
||||
JsonSerializerSettings serializerSettings,
|
||||
ArrayPool<char> charPool)
|
||||
: base(logger, serializerSettings, charPool)
|
||||
ArrayPool<char> charPool,
|
||||
ObjectPoolProvider objectPoolProvider)
|
||||
: base(logger, serializerSettings, charPool, objectPoolProvider)
|
||||
{
|
||||
// Clear all values and only include json-patch+json value.
|
||||
SupportedMediaTypes.Clear();
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using Microsoft.AspNet.Mvc.ModelBinding;
|
|||
using Microsoft.AspNet.Mvc.ModelBinding.Metadata;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||
|
|
@ -31,7 +32,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
|||
var loggerFactory = new LoggerFactory();
|
||||
var serializerSettings = SerializerSettingsProvider.CreateSerializerSettings();
|
||||
|
||||
MvcJsonMvcOptionsSetup.ConfigureMvc(Value, serializerSettings, loggerFactory, ArrayPool<char>.Shared);
|
||||
MvcJsonMvcOptionsSetup.ConfigureMvc(
|
||||
Value,
|
||||
serializerSettings,
|
||||
loggerFactory,
|
||||
ArrayPool<char>.Shared,
|
||||
new DefaultObjectPoolProvider());
|
||||
}
|
||||
|
||||
public MvcOptions Value { get; }
|
||||
|
|
|
|||
Loading…
Reference in New Issue