[Fixes #6858] Changes to MvcOption's settings (SuppressInputFormatterBuffering & AllowBindingUndefinedValueToEnumType) are not taking affect
This commit is contained in:
parent
3ca5955b31
commit
629f87181a
|
|
@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
options.ModelBinderProviders.Add(new BodyModelBinderProvider(options.InputFormatters, _readerFactory, _loggerFactory, options));
|
options.ModelBinderProviders.Add(new BodyModelBinderProvider(options.InputFormatters, _readerFactory, _loggerFactory, options));
|
||||||
options.ModelBinderProviders.Add(new HeaderModelBinderProvider());
|
options.ModelBinderProviders.Add(new HeaderModelBinderProvider());
|
||||||
options.ModelBinderProviders.Add(new FloatingPointTypeModelBinderProvider());
|
options.ModelBinderProviders.Add(new FloatingPointTypeModelBinderProvider());
|
||||||
options.ModelBinderProviders.Add(new EnumTypeModelBinderProvider(options.AllowBindingUndefinedValueToEnumType));
|
options.ModelBinderProviders.Add(new EnumTypeModelBinderProvider(options));
|
||||||
options.ModelBinderProviders.Add(new SimpleTypeModelBinderProvider());
|
options.ModelBinderProviders.Add(new SimpleTypeModelBinderProvider());
|
||||||
options.ModelBinderProviders.Add(new CancellationTokenModelBinderProvider());
|
options.ModelBinderProviders.Add(new CancellationTokenModelBinderProvider());
|
||||||
options.ModelBinderProviders.Add(new ByteArrayModelBinderProvider());
|
options.ModelBinderProviders.Add(new ByteArrayModelBinderProvider());
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,11 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class EnumTypeModelBinderProvider : IModelBinderProvider
|
public class EnumTypeModelBinderProvider : IModelBinderProvider
|
||||||
{
|
{
|
||||||
private readonly bool _allowBindingUndefinedValueToEnumType;
|
private readonly MvcOptions _options;
|
||||||
|
|
||||||
public EnumTypeModelBinderProvider(bool allowBindingUndefinedValueToEnumType)
|
public EnumTypeModelBinderProvider(MvcOptions options)
|
||||||
{
|
{
|
||||||
_allowBindingUndefinedValueToEnumType = allowBindingUndefinedValueToEnumType;
|
_options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
if (context.Metadata.IsEnum)
|
if (context.Metadata.IsEnum)
|
||||||
{
|
{
|
||||||
return new EnumTypeModelBinder(
|
return new EnumTypeModelBinder(
|
||||||
_allowBindingUndefinedValueToEnumType,
|
_options.AllowBindingUndefinedValueToEnumType,
|
||||||
context.Metadata.UnderlyingOrModelType);
|
context.Metadata.UnderlyingOrModelType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,8 +69,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Json.Internal
|
||||||
_jsonSerializerSettings,
|
_jsonSerializerSettings,
|
||||||
_charPool,
|
_charPool,
|
||||||
_objectPoolProvider,
|
_objectPoolProvider,
|
||||||
options.SuppressInputFormatterBuffering,
|
options));
|
||||||
options.SuppressJsonDeserializationExceptionMessagesInModelState));
|
|
||||||
|
|
||||||
var jsonInputLogger = _loggerFactory.CreateLogger<JsonInputFormatter>();
|
var jsonInputLogger = _loggerFactory.CreateLogger<JsonInputFormatter>();
|
||||||
options.InputFormatters.Add(new JsonInputFormatter(
|
options.InputFormatters.Add(new JsonInputFormatter(
|
||||||
|
|
@ -78,8 +77,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Json.Internal
|
||||||
_jsonSerializerSettings,
|
_jsonSerializerSettings,
|
||||||
_charPool,
|
_charPool,
|
||||||
_objectPoolProvider,
|
_objectPoolProvider,
|
||||||
options.SuppressInputFormatterBuffering,
|
options));
|
||||||
options.SuppressJsonDeserializationExceptionMessagesInModelState));
|
|
||||||
|
|
||||||
options.FormatterMappings.SetMediaTypeMappingForFormat("json", MediaTypeHeaderValue.Parse("application/json"));
|
options.FormatterMappings.SetMediaTypeMappingForFormat("json", MediaTypeHeaderValue.Parse("application/json"));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
private readonly IArrayPool<char> _charPool;
|
private readonly IArrayPool<char> _charPool;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly ObjectPoolProvider _objectPoolProvider;
|
private readonly ObjectPoolProvider _objectPoolProvider;
|
||||||
|
private readonly MvcOptions _options;
|
||||||
private readonly bool _suppressInputFormatterBuffering;
|
private readonly bool _suppressInputFormatterBuffering;
|
||||||
private readonly bool _suppressJsonDeserializationExceptionMessages;
|
private readonly bool _suppressJsonDeserializationExceptionMessages;
|
||||||
|
|
||||||
|
|
@ -43,6 +44,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
/// </param>
|
/// </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>
|
||||||
|
[Obsolete("This constructor is obsolete and will be removed in a future version.")]
|
||||||
public JsonInputFormatter(
|
public JsonInputFormatter(
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
JsonSerializerSettings serializerSettings,
|
JsonSerializerSettings serializerSettings,
|
||||||
|
|
@ -65,6 +67,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
/// <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>
|
||||||
/// <param name="suppressInputFormatterBuffering">Flag to buffer entire request body before deserializing it.</param>
|
/// <param name="suppressInputFormatterBuffering">Flag to buffer entire request body before deserializing it.</param>
|
||||||
|
[Obsolete("This constructor is obsolete and will be removed in a future version.")]
|
||||||
public JsonInputFormatter(
|
public JsonInputFormatter(
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
JsonSerializerSettings serializerSettings,
|
JsonSerializerSettings serializerSettings,
|
||||||
|
|
@ -90,6 +93,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
/// <param name="objectPoolProvider">The <see cref="ObjectPoolProvider"/>.</param>
|
/// <param name="objectPoolProvider">The <see cref="ObjectPoolProvider"/>.</param>
|
||||||
/// <param name="suppressInputFormatterBuffering">Flag to buffer entire request body before deserializing it.</param>
|
/// <param name="suppressInputFormatterBuffering">Flag to buffer entire request body before deserializing it.</param>
|
||||||
/// <param name="suppressJsonDeserializationExceptionMessages">If <see langword="true"/>, JSON deserialization exception messages will replaced by a generic message in model state.</param>
|
/// <param name="suppressJsonDeserializationExceptionMessages">If <see langword="true"/>, JSON deserialization exception messages will replaced by a generic message in model state.</param>
|
||||||
|
[Obsolete("This constructor is obsolete and will be removed in a future version.")]
|
||||||
public JsonInputFormatter(
|
public JsonInputFormatter(
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
JsonSerializerSettings serializerSettings,
|
JsonSerializerSettings serializerSettings,
|
||||||
|
|
@ -133,6 +137,59 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationAnyJsonSyntax);
|
SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationAnyJsonSyntax);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <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"/>. 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>
|
||||||
|
/// <param name="options">The <see cref="MvcOptions"/>.</param>
|
||||||
|
public JsonInputFormatter(
|
||||||
|
ILogger logger,
|
||||||
|
JsonSerializerSettings serializerSettings,
|
||||||
|
ArrayPool<char> charPool,
|
||||||
|
ObjectPoolProvider objectPoolProvider,
|
||||||
|
MvcOptions options)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
_options = options;
|
||||||
|
|
||||||
|
SupportedEncodings.Add(UTF8EncodingWithoutBOM);
|
||||||
|
SupportedEncodings.Add(UTF16EncodingLittleEndian);
|
||||||
|
|
||||||
|
SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationJson);
|
||||||
|
SupportedMediaTypes.Add(MediaTypeHeaderValues.TextJson);
|
||||||
|
SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationAnyJsonSyntax);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual InputFormatterExceptionModelStatePolicy ExceptionPolicy
|
public virtual InputFormatterExceptionModelStatePolicy ExceptionPolicy
|
||||||
{
|
{
|
||||||
|
|
@ -172,7 +229,9 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
|
|
||||||
var request = context.HttpContext.Request;
|
var request = context.HttpContext.Request;
|
||||||
|
|
||||||
if (!request.Body.CanSeek && !_suppressInputFormatterBuffering)
|
var suppressInputFormatterBuffering = _options?.SuppressInputFormatterBuffering ?? _suppressInputFormatterBuffering;
|
||||||
|
|
||||||
|
if (!request.Body.CanSeek && !suppressInputFormatterBuffering)
|
||||||
{
|
{
|
||||||
// JSON.Net does synchronous reads. In order to avoid blocking on the stream, we asynchronously
|
// JSON.Net does synchronous reads. In order to avoid blocking on the stream, we asynchronously
|
||||||
// read everything into a buffer, and then seek back to the beginning.
|
// read everything into a buffer, and then seek back to the beginning.
|
||||||
|
|
@ -352,8 +411,9 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
// we regard as having safe messages to expose to clients
|
// we regard as having safe messages to expose to clients
|
||||||
var isJsonExceptionType =
|
var isJsonExceptionType =
|
||||||
exception is JsonReaderException || exception is JsonSerializationException;
|
exception is JsonReaderException || exception is JsonSerializationException;
|
||||||
|
var suppressJsonDeserializationExceptionMessages = _options?.SuppressJsonDeserializationExceptionMessagesInModelState ?? _suppressJsonDeserializationExceptionMessages;
|
||||||
var suppressOriginalMessage =
|
var suppressOriginalMessage =
|
||||||
_suppressJsonDeserializationExceptionMessages || !isJsonExceptionType;
|
suppressJsonDeserializationExceptionMessages || !isJsonExceptionType;
|
||||||
return suppressOriginalMessage
|
return suppressOriginalMessage
|
||||||
? exception
|
? exception
|
||||||
: new InputFormatterException(exception.Message, exception);
|
: new InputFormatterException(exception.Message, exception);
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
/// </param>
|
/// </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>
|
||||||
|
[Obsolete("This constructor is obsolete and will be removed in a future version.")]
|
||||||
public JsonPatchInputFormatter(
|
public JsonPatchInputFormatter(
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
JsonSerializerSettings serializerSettings,
|
JsonSerializerSettings serializerSettings,
|
||||||
|
|
@ -51,6 +52,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
/// <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>
|
||||||
/// <param name="suppressInputFormatterBuffering">Flag to buffer entire request body before deserializing it.</param>
|
/// <param name="suppressInputFormatterBuffering">Flag to buffer entire request body before deserializing it.</param>
|
||||||
|
[Obsolete("This constructor is obsolete and will be removed in a future version.")]
|
||||||
public JsonPatchInputFormatter(
|
public JsonPatchInputFormatter(
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
JsonSerializerSettings serializerSettings,
|
JsonSerializerSettings serializerSettings,
|
||||||
|
|
@ -74,6 +76,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
/// <param name="objectPoolProvider">The <see cref="ObjectPoolProvider"/>.</param>
|
/// <param name="objectPoolProvider">The <see cref="ObjectPoolProvider"/>.</param>
|
||||||
/// <param name="suppressInputFormatterBuffering">Flag to buffer entire request body before deserializing it.</param>
|
/// <param name="suppressInputFormatterBuffering">Flag to buffer entire request body before deserializing it.</param>
|
||||||
/// <param name="suppressJsonDeserializationExceptionMessages">If <see langword="true"/>, JSON deserialization exception messages will replaced by a generic message in model state.</param>
|
/// <param name="suppressJsonDeserializationExceptionMessages">If <see langword="true"/>, JSON deserialization exception messages will replaced by a generic message in model state.</param>
|
||||||
|
[Obsolete("This constructor is obsolete and will be removed in a future version.")]
|
||||||
public JsonPatchInputFormatter(
|
public JsonPatchInputFormatter(
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
JsonSerializerSettings serializerSettings,
|
JsonSerializerSettings serializerSettings,
|
||||||
|
|
@ -89,6 +92,32 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationJsonPatch);
|
SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationJsonPatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
/// <param name="options">The <see cref="MvcOptions"/>.</param>
|
||||||
|
public JsonPatchInputFormatter(
|
||||||
|
ILogger logger,
|
||||||
|
JsonSerializerSettings serializerSettings,
|
||||||
|
ArrayPool<char> charPool,
|
||||||
|
ObjectPoolProvider objectPoolProvider,
|
||||||
|
MvcOptions options)
|
||||||
|
: base(logger, serializerSettings, charPool, objectPoolProvider, options)
|
||||||
|
{
|
||||||
|
// Clear all values and only include json-patch+json value.
|
||||||
|
SupportedMediaTypes.Clear();
|
||||||
|
|
||||||
|
SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationJsonPatch);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override InputFormatterExceptionModelStatePolicy ExceptionPolicy
|
public override InputFormatterExceptionModelStatePolicy ExceptionPolicy
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -799,7 +799,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
private readonly bool _throwNonInputFormatterException;
|
private readonly bool _throwNonInputFormatterException;
|
||||||
|
|
||||||
public TestableJsonInputFormatter(bool throwNonInputFormatterException)
|
public TestableJsonInputFormatter(bool throwNonInputFormatterException)
|
||||||
: base(GetLogger(), new JsonSerializerSettings(), ArrayPool<char>.Shared, new DefaultObjectPoolProvider())
|
: base(GetLogger(), new JsonSerializerSettings(), ArrayPool<char>.Shared, new DefaultObjectPoolProvider(), new MvcOptions())
|
||||||
{
|
{
|
||||||
_throwNonInputFormatterException = throwNonInputFormatterException;
|
_throwNonInputFormatterException = throwNonInputFormatterException;
|
||||||
}
|
}
|
||||||
|
|
@ -863,7 +863,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
private readonly bool _throwNonInputFormatterException;
|
private readonly bool _throwNonInputFormatterException;
|
||||||
|
|
||||||
public DerivedJsonInputFormatter(bool throwNonInputFormatterException)
|
public DerivedJsonInputFormatter(bool throwNonInputFormatterException)
|
||||||
: base(GetLogger(), new JsonSerializerSettings(), ArrayPool<char>.Shared, new DefaultObjectPoolProvider())
|
: base(GetLogger(), new JsonSerializerSettings(), ArrayPool<char>.Shared, new DefaultObjectPoolProvider(), new MvcOptions())
|
||||||
{
|
{
|
||||||
_throwNonInputFormatterException = throwNonInputFormatterException;
|
_throwNonInputFormatterException = throwNonInputFormatterException;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
public void ReturnsBinder_ForEnumType(Type modelType)
|
public void ReturnsBinder_ForEnumType(Type modelType)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var provider = new EnumTypeModelBinderProvider(allowBindingUndefinedValueToEnumType: true);
|
var provider = new EnumTypeModelBinderProvider(new MvcOptions { AllowBindingUndefinedValueToEnumType = true });
|
||||||
var context = new TestModelBinderProviderContext(modelType);
|
var context = new TestModelBinderProviderContext(modelType);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
public void ReturnsBinder_ForFlagsEnumType(Type modelType)
|
public void ReturnsBinder_ForFlagsEnumType(Type modelType)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var provider = new EnumTypeModelBinderProvider(allowBindingUndefinedValueToEnumType: true);
|
var provider = new EnumTypeModelBinderProvider(new MvcOptions { AllowBindingUndefinedValueToEnumType = true });
|
||||||
var context = new TestModelBinderProviderContext(modelType);
|
var context = new TestModelBinderProviderContext(modelType);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
public void DoesNotReturnBinder_ForNonEnumTypes(Type modelType)
|
public void DoesNotReturnBinder_ForNonEnumTypes(Type modelType)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var provider = new EnumTypeModelBinderProvider(allowBindingUndefinedValueToEnumType: false);
|
var provider = new EnumTypeModelBinderProvider(new MvcOptions { AllowBindingUndefinedValueToEnumType = false });
|
||||||
var context = new TestModelBinderProviderContext(modelType);
|
var context = new TestModelBinderProviderContext(modelType);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
|
|
@ -281,7 +282,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
{ modelName, valueProviderValue }
|
{ modelName, valueProviderValue }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var binderProvider = new EnumTypeModelBinderProvider(allowBindingUndefinedValueToEnumType);
|
var binderProvider = new EnumTypeModelBinderProvider(new MvcOptions
|
||||||
|
{
|
||||||
|
AllowBindingUndefinedValueToEnumType = allowBindingUndefinedValueToEnumType
|
||||||
|
});
|
||||||
var binder = binderProvider.GetBinder(binderProviderContext);
|
var binder = binderProvider.GetBinder(binderProviderContext);
|
||||||
return (bindingContext, binder);
|
return (bindingContext, binder);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,59 @@ 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();
|
||||||
|
#pragma warning disable CS0618
|
||||||
var formatter =
|
var formatter =
|
||||||
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
||||||
|
#pragma warning restore CS0618
|
||||||
|
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
|
||||||
|
var modelState = new ModelStateDictionary();
|
||||||
|
var httpContext = new DefaultHttpContext();
|
||||||
|
httpContext.Features.Set<IHttpResponseFeature>(new TestResponseFeature());
|
||||||
|
httpContext.Request.Body = new NonSeekableReadStream(contentBytes);
|
||||||
|
httpContext.Request.ContentType = "application/json";
|
||||||
|
var provider = new EmptyModelMetadataProvider();
|
||||||
|
var metadata = provider.GetMetadataForType(typeof(User));
|
||||||
|
var context = new InputFormatterContext(
|
||||||
|
httpContext,
|
||||||
|
modelName: string.Empty,
|
||||||
|
modelState: modelState,
|
||||||
|
metadata: metadata,
|
||||||
|
readerFactory: new TestHttpRequestStreamReaderFactory().CreateReader);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result.HasError);
|
||||||
|
var userModel = Assert.IsType<User>(result.Model);
|
||||||
|
Assert.Equal("Person Name", userModel.Name);
|
||||||
|
Assert.Equal(30, userModel.Age);
|
||||||
|
|
||||||
|
Assert.True(httpContext.Request.Body.CanSeek);
|
||||||
|
httpContext.Request.Body.Seek(0L, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
result = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result.HasError);
|
||||||
|
userModel = Assert.IsType<User>(result.Model);
|
||||||
|
Assert.Equal("Person Name", userModel.Name);
|
||||||
|
Assert.Equal(30, userModel.Age);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task BuffersRequestBody_UsingDefaultOptions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var content = "{name: 'Person Name', Age: '30'}";
|
||||||
|
var logger = GetLogger();
|
||||||
|
var formatter = new JsonInputFormatter(
|
||||||
|
logger,
|
||||||
|
_serializerSettings,
|
||||||
|
ArrayPool<char>.Shared,
|
||||||
|
_objectPoolProvider,
|
||||||
|
new MvcOptions());
|
||||||
var contentBytes = Encoding.UTF8.GetBytes(content);
|
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
|
||||||
var modelState = new ModelStateDictionary();
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
@ -78,8 +129,10 @@ 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();
|
||||||
|
#pragma warning disable CS0618
|
||||||
var formatter =
|
var formatter =
|
||||||
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, suppressInputFormatterBuffering: true);
|
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, suppressInputFormatterBuffering: true);
|
||||||
|
#pragma warning restore CS0618
|
||||||
var contentBytes = Encoding.UTF8.GetBytes(content);
|
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
|
||||||
var modelState = new ModelStateDictionary();
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
@ -105,7 +158,99 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
Assert.Equal("Person Name", userModel.Name);
|
Assert.Equal("Person Name", userModel.Name);
|
||||||
Assert.Equal(30, userModel.Age);
|
Assert.Equal(30, userModel.Age);
|
||||||
|
|
||||||
// Reading again should not fail as the request body should have been buffered by the formatter
|
Assert.False(httpContext.Request.Body.CanSeek);
|
||||||
|
result = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result.HasError);
|
||||||
|
Assert.Null(result.Model);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SuppressInputFormatterBufferingSetToTrue_UsingMvcOptions_DoesNotBufferRequestBody()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var content = "{name: 'Person Name', Age: '30'}";
|
||||||
|
var logger = GetLogger();
|
||||||
|
var mvcOptions = new MvcOptions();
|
||||||
|
mvcOptions.SuppressInputFormatterBuffering = true;
|
||||||
|
var formatter = new JsonInputFormatter(
|
||||||
|
logger,
|
||||||
|
_serializerSettings,
|
||||||
|
ArrayPool<char>.Shared,
|
||||||
|
_objectPoolProvider,
|
||||||
|
mvcOptions);
|
||||||
|
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
|
||||||
|
var modelState = new ModelStateDictionary();
|
||||||
|
var httpContext = new DefaultHttpContext();
|
||||||
|
httpContext.Features.Set<IHttpResponseFeature>(new TestResponseFeature());
|
||||||
|
httpContext.Request.Body = new NonSeekableReadStream(contentBytes);
|
||||||
|
httpContext.Request.ContentType = "application/json";
|
||||||
|
var provider = new EmptyModelMetadataProvider();
|
||||||
|
var metadata = provider.GetMetadataForType(typeof(User));
|
||||||
|
var context = new InputFormatterContext(
|
||||||
|
httpContext,
|
||||||
|
modelName: string.Empty,
|
||||||
|
modelState: modelState,
|
||||||
|
metadata: metadata,
|
||||||
|
readerFactory: new TestHttpRequestStreamReaderFactory().CreateReader);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result.HasError);
|
||||||
|
var userModel = Assert.IsType<User>(result.Model);
|
||||||
|
Assert.Equal("Person Name", userModel.Name);
|
||||||
|
Assert.Equal(30, userModel.Age);
|
||||||
|
|
||||||
|
Assert.False(httpContext.Request.Body.CanSeek);
|
||||||
|
result = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result.HasError);
|
||||||
|
Assert.Null(result.Model);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SuppressInputFormatterBufferingSetToTrue_UsingMutatedOptions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var content = "{name: 'Person Name', Age: '30'}";
|
||||||
|
var logger = GetLogger();
|
||||||
|
var mvcOptions = new MvcOptions();
|
||||||
|
mvcOptions.SuppressInputFormatterBuffering = false;
|
||||||
|
var formatter =
|
||||||
|
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, mvcOptions);
|
||||||
|
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
|
||||||
|
var modelState = new ModelStateDictionary();
|
||||||
|
var httpContext = new DefaultHttpContext();
|
||||||
|
httpContext.Features.Set<IHttpResponseFeature>(new TestResponseFeature());
|
||||||
|
httpContext.Request.Body = new NonSeekableReadStream(contentBytes);
|
||||||
|
httpContext.Request.ContentType = "application/json";
|
||||||
|
var provider = new EmptyModelMetadataProvider();
|
||||||
|
var metadata = provider.GetMetadataForType(typeof(User));
|
||||||
|
var context = new InputFormatterContext(
|
||||||
|
httpContext,
|
||||||
|
modelName: string.Empty,
|
||||||
|
modelState: modelState,
|
||||||
|
metadata: metadata,
|
||||||
|
readerFactory: new TestHttpRequestStreamReaderFactory().CreateReader);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
// Mutate options after passing into the constructor to make sure that the value type is not store in the constructor
|
||||||
|
mvcOptions.SuppressInputFormatterBuffering = true;
|
||||||
|
var result = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result.HasError);
|
||||||
|
var userModel = Assert.IsType<User>(result.Model);
|
||||||
|
Assert.Equal("Person Name", userModel.Name);
|
||||||
|
Assert.Equal(30, userModel.Age);
|
||||||
|
|
||||||
|
Assert.False(httpContext.Request.Body.CanSeek);
|
||||||
result = await formatter.ReadAsync(context);
|
result = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -135,7 +280,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
var loggerMock = GetLogger();
|
var loggerMock = GetLogger();
|
||||||
|
|
||||||
var formatter =
|
var formatter =
|
||||||
new JsonInputFormatter(loggerMock, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
new JsonInputFormatter(loggerMock, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions());
|
||||||
var contentBytes = Encoding.UTF8.GetBytes("content");
|
var contentBytes = Encoding.UTF8.GetBytes("content");
|
||||||
|
|
||||||
var httpContext = GetHttpContext(contentBytes, contentType: requestContentType);
|
var httpContext = GetHttpContext(contentBytes, contentType: requestContentType);
|
||||||
|
|
@ -161,7 +306,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
// Arrange
|
// Arrange
|
||||||
var loggerMock = GetLogger();
|
var loggerMock = GetLogger();
|
||||||
var formatter =
|
var formatter =
|
||||||
new JsonInputFormatter(loggerMock, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
new JsonInputFormatter(loggerMock, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var mediaType = formatter.SupportedMediaTypes[0];
|
var mediaType = formatter.SupportedMediaTypes[0];
|
||||||
|
|
@ -188,7 +333,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
// Arrange
|
// Arrange
|
||||||
var logger = GetLogger();
|
var logger = GetLogger();
|
||||||
var formatter =
|
var formatter =
|
||||||
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions());
|
||||||
var contentBytes = Encoding.UTF8.GetBytes(content);
|
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
|
||||||
var httpContext = GetHttpContext(contentBytes);
|
var httpContext = GetHttpContext(contentBytes);
|
||||||
|
|
@ -216,7 +361,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
var content = "{name: 'Person Name', Age: '30'}";
|
var content = "{name: 'Person Name', Age: '30'}";
|
||||||
var logger = GetLogger();
|
var logger = GetLogger();
|
||||||
var formatter =
|
var formatter =
|
||||||
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions());
|
||||||
var contentBytes = Encoding.UTF8.GetBytes(content);
|
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
|
||||||
var httpContext = GetHttpContext(contentBytes);
|
var httpContext = GetHttpContext(contentBytes);
|
||||||
|
|
@ -246,7 +391,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
var content = "[0, 23, 300]";
|
var content = "[0, 23, 300]";
|
||||||
var logger = GetLogger();
|
var logger = GetLogger();
|
||||||
var formatter =
|
var formatter =
|
||||||
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions());
|
||||||
var contentBytes = Encoding.UTF8.GetBytes(content);
|
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
|
||||||
var modelState = new ModelStateDictionary();
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
@ -280,7 +425,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
var content = "[0, 23, 300]";
|
var content = "[0, 23, 300]";
|
||||||
var logger = GetLogger();
|
var logger = GetLogger();
|
||||||
var formatter =
|
var formatter =
|
||||||
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions());
|
||||||
var contentBytes = Encoding.UTF8.GetBytes(content);
|
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
|
||||||
var modelState = new ModelStateDictionary();
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
@ -310,7 +455,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
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 =
|
var formatter =
|
||||||
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions());
|
||||||
var contentBytes = Encoding.UTF8.GetBytes(content);
|
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
|
||||||
var modelState = new ModelStateDictionary();
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
@ -341,7 +486,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
var content = "[0, 23, 300]";
|
var content = "[0, 23, 300]";
|
||||||
var logger = GetLogger();
|
var logger = GetLogger();
|
||||||
var formatter =
|
var formatter =
|
||||||
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions());
|
||||||
var contentBytes = Encoding.UTF8.GetBytes(content);
|
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
|
||||||
var modelState = new ModelStateDictionary();
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
@ -371,7 +516,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
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 =
|
var formatter =
|
||||||
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions());
|
||||||
var contentBytes = Encoding.UTF8.GetBytes(content);
|
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
|
||||||
var modelState = new ModelStateDictionary();
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
@ -402,7 +547,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
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 =
|
var formatter =
|
||||||
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions());
|
||||||
var contentBytes = Encoding.UTF8.GetBytes(content);
|
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
|
||||||
var modelState = new ModelStateDictionary();
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
@ -440,7 +585,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
// Arrange
|
// Arrange
|
||||||
var logger = GetLogger();
|
var logger = GetLogger();
|
||||||
var formatter =
|
var formatter =
|
||||||
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions());
|
||||||
var contentBytes = Encoding.UTF8.GetBytes(content);
|
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
|
||||||
var modelState = new ModelStateDictionary();
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
@ -488,7 +633,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
// by default we ignore missing members, so here explicitly changing it
|
// by default we ignore missing members, so here explicitly changing it
|
||||||
var serializerSettings = new JsonSerializerSettings { MissingMemberHandling = MissingMemberHandling.Error };
|
var serializerSettings = new JsonSerializerSettings { MissingMemberHandling = MissingMemberHandling.Error };
|
||||||
var jsonFormatter =
|
var jsonFormatter =
|
||||||
new JsonInputFormatter(logger, serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
new JsonInputFormatter(logger, serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions());
|
||||||
|
|
||||||
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");
|
||||||
|
|
@ -547,7 +692,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
// Arrange
|
// Arrange
|
||||||
var logger = GetLogger();
|
var logger = GetLogger();
|
||||||
var formatter =
|
var formatter =
|
||||||
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
new JsonInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions());
|
||||||
var contentBytes = Encoding.UTF8.GetBytes(content);
|
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
|
||||||
var modelState = new ModelStateDictionary();
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
@ -579,8 +724,15 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
// Arrange
|
// Arrange
|
||||||
var logger = GetLogger();
|
var logger = GetLogger();
|
||||||
var formatter = new JsonInputFormatter(
|
var formatter = new JsonInputFormatter(
|
||||||
logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider,
|
logger,
|
||||||
suppressInputFormatterBuffering: false, suppressJsonDeserializationExceptionMessages: true);
|
_serializerSettings,
|
||||||
|
ArrayPool<char>.Shared,
|
||||||
|
_objectPoolProvider,
|
||||||
|
new MvcOptions()
|
||||||
|
{
|
||||||
|
SuppressInputFormatterBuffering = false,
|
||||||
|
SuppressJsonDeserializationExceptionMessagesInModelState = true
|
||||||
|
});
|
||||||
var contentBytes = Encoding.UTF8.GetBytes("{");
|
var contentBytes = Encoding.UTF8.GetBytes("{");
|
||||||
var modelStateKey = string.Empty;
|
var modelStateKey = string.Empty;
|
||||||
|
|
||||||
|
|
@ -611,7 +763,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
private class TestableJsonInputFormatter : JsonInputFormatter
|
private class TestableJsonInputFormatter : JsonInputFormatter
|
||||||
{
|
{
|
||||||
public TestableJsonInputFormatter(JsonSerializerSettings settings)
|
public TestableJsonInputFormatter(JsonSerializerSettings settings)
|
||||||
: base(GetLogger(), settings, ArrayPool<char>.Shared, _objectPoolProvider)
|
: base(GetLogger(), settings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,57 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var logger = GetLogger();
|
var logger = GetLogger();
|
||||||
|
#pragma warning disable CS0618
|
||||||
var formatter =
|
var formatter =
|
||||||
new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
||||||
|
#pragma warning restore CS0618
|
||||||
|
var content = "[{\"op\":\"add\",\"path\":\"Customer/Name\",\"value\":\"John\"}]";
|
||||||
|
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
|
||||||
|
var modelState = new ModelStateDictionary();
|
||||||
|
var httpContext = new DefaultHttpContext();
|
||||||
|
httpContext.Features.Set<IHttpResponseFeature>(new TestResponseFeature());
|
||||||
|
httpContext.Request.Body = new NonSeekableReadStream(contentBytes);
|
||||||
|
httpContext.Request.ContentType = "application/json";
|
||||||
|
var provider = new EmptyModelMetadataProvider();
|
||||||
|
var metadata = provider.GetMetadataForType(typeof(JsonPatchDocument<Customer>));
|
||||||
|
var context = new InputFormatterContext(
|
||||||
|
httpContext,
|
||||||
|
modelName: string.Empty,
|
||||||
|
modelState: modelState,
|
||||||
|
metadata: metadata,
|
||||||
|
readerFactory: new TestHttpRequestStreamReaderFactory().CreateReader);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result.HasError);
|
||||||
|
var patchDoc = Assert.IsType<JsonPatchDocument<Customer>>(result.Model);
|
||||||
|
Assert.Equal("add", patchDoc.Operations[0].op);
|
||||||
|
Assert.Equal("Customer/Name", patchDoc.Operations[0].path);
|
||||||
|
Assert.Equal("John", patchDoc.Operations[0].value);
|
||||||
|
|
||||||
|
Assert.True(httpContext.Request.Body.CanSeek);
|
||||||
|
httpContext.Request.Body.Seek(0L, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
result = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result.HasError);
|
||||||
|
patchDoc = Assert.IsType<JsonPatchDocument<Customer>>(result.Model);
|
||||||
|
Assert.Equal("add", patchDoc.Operations[0].op);
|
||||||
|
Assert.Equal("Customer/Name", patchDoc.Operations[0].path);
|
||||||
|
Assert.Equal("John", patchDoc.Operations[0].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task BuffersRequestBody_UsingDefaultOptions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var logger = GetLogger();
|
||||||
|
var formatter =
|
||||||
|
new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions());
|
||||||
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);
|
||||||
|
|
||||||
|
|
@ -77,8 +126,10 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var logger = GetLogger();
|
var logger = GetLogger();
|
||||||
|
#pragma warning disable CS0618
|
||||||
var formatter =
|
var formatter =
|
||||||
new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, suppressInputFormatterBuffering: true);
|
new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, suppressInputFormatterBuffering: true);
|
||||||
|
#pragma warning restore CS0618
|
||||||
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);
|
||||||
|
|
||||||
|
|
@ -106,6 +157,57 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
Assert.Equal("Customer/Name", patchDoc.Operations[0].path);
|
Assert.Equal("Customer/Name", patchDoc.Operations[0].path);
|
||||||
Assert.Equal("John", patchDoc.Operations[0].value);
|
Assert.Equal("John", patchDoc.Operations[0].value);
|
||||||
|
|
||||||
|
Assert.False(httpContext.Request.Body.CanSeek);
|
||||||
|
result = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result.HasError);
|
||||||
|
Assert.Null(result.Model);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SuppressInputFormatterBufferingSetToTrue_UsingMutatedOptions_DoesNotBufferRequestBody()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var logger = GetLogger();
|
||||||
|
var mvcOptions = new MvcOptions();
|
||||||
|
mvcOptions.SuppressInputFormatterBuffering = false;
|
||||||
|
var formatter = new JsonPatchInputFormatter(
|
||||||
|
logger,
|
||||||
|
_serializerSettings,
|
||||||
|
ArrayPool<char>.Shared,
|
||||||
|
_objectPoolProvider,
|
||||||
|
mvcOptions);
|
||||||
|
var content = "[{\"op\":\"add\",\"path\":\"Customer/Name\",\"value\":\"John\"}]";
|
||||||
|
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
|
||||||
|
var modelState = new ModelStateDictionary();
|
||||||
|
var httpContext = new DefaultHttpContext();
|
||||||
|
httpContext.Features.Set<IHttpResponseFeature>(new TestResponseFeature());
|
||||||
|
httpContext.Request.Body = new NonSeekableReadStream(contentBytes);
|
||||||
|
httpContext.Request.ContentType = "application/json";
|
||||||
|
var provider = new EmptyModelMetadataProvider();
|
||||||
|
var metadata = provider.GetMetadataForType(typeof(JsonPatchDocument<Customer>));
|
||||||
|
var context = new InputFormatterContext(
|
||||||
|
httpContext,
|
||||||
|
modelName: string.Empty,
|
||||||
|
modelState: modelState,
|
||||||
|
metadata: metadata,
|
||||||
|
readerFactory: new TestHttpRequestStreamReaderFactory().CreateReader);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
// Mutate options after passing into the constructor to make sure that the value type is not store in the constructor
|
||||||
|
mvcOptions.SuppressInputFormatterBuffering = true;
|
||||||
|
var result = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result.HasError);
|
||||||
|
var patchDoc = Assert.IsType<JsonPatchDocument<Customer>>(result.Model);
|
||||||
|
Assert.Equal("add", patchDoc.Operations[0].op);
|
||||||
|
Assert.Equal("Customer/Name", patchDoc.Operations[0].path);
|
||||||
|
Assert.Equal("John", patchDoc.Operations[0].value);
|
||||||
|
|
||||||
|
Assert.False(httpContext.Request.Body.CanSeek);
|
||||||
result = await formatter.ReadAsync(context);
|
result = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -119,7 +221,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
// Arrange
|
// Arrange
|
||||||
var logger = GetLogger();
|
var logger = GetLogger();
|
||||||
var formatter =
|
var formatter =
|
||||||
new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions());
|
||||||
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 +253,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
// Arrange
|
// Arrange
|
||||||
var logger = GetLogger();
|
var logger = GetLogger();
|
||||||
var formatter =
|
var formatter =
|
||||||
new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions());
|
||||||
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);
|
||||||
|
|
@ -190,7 +292,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
// Arrange
|
// Arrange
|
||||||
var logger = GetLogger();
|
var logger = GetLogger();
|
||||||
var formatter =
|
var formatter =
|
||||||
new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions());
|
||||||
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);
|
||||||
|
|
||||||
|
|
@ -220,7 +322,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
// Arrange
|
// Arrange
|
||||||
var logger = GetLogger();
|
var logger = GetLogger();
|
||||||
var formatter =
|
var formatter =
|
||||||
new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions());
|
||||||
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);
|
||||||
|
|
||||||
|
|
@ -251,7 +353,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
|
|
||||||
var logger = GetLogger();
|
var logger = GetLogger();
|
||||||
var formatter =
|
var formatter =
|
||||||
new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider);
|
new JsonPatchInputFormatter(logger, _serializerSettings, ArrayPool<char>.Shared, _objectPoolProvider, new MvcOptions());
|
||||||
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);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue