Update the Enum Invalid Value setting for compat
Updated the naming to follow guidelines, and set the default for 2.0 apps to false. Note that I inverted the naming, which means that I had to invert the logic in a few places.
This commit is contained in:
parent
514381f16f
commit
82e32240a4
|
|
@ -48,6 +48,14 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// Sets the default value of settings on <see cref="MvcOptions"/> to match the behavior of
|
||||
/// ASP.NET Core MVC 2.1.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// ASP.NET Core MVC 2.1 introduces compatibility switches for the following:
|
||||
/// <list type="bullet">
|
||||
/// <item>
|
||||
/// <description><see cref="MvcOptions.SuppressBindingUndefinedValueToEnumType"/></description>
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
Version_2_1,
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
|
||||
if (Version >= CompatibilityVersion.Version_2_1)
|
||||
{
|
||||
values[nameof(MvcOptions.SuppressBindingUndefinedValueToEnumType)] = true;
|
||||
values[nameof(MvcOptions.InputFormatterExceptionModelStatePolicy)] = InputFormatterExceptionModelStatePolicy.MalformedInputExceptions;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
/// </summary>
|
||||
public class EnumTypeModelBinder : SimpleTypeModelBinder
|
||||
{
|
||||
private readonly bool _allowBindingUndefinedValueToEnumType;
|
||||
private readonly bool _suppressBindingUndefinedValueToEnumType;
|
||||
|
||||
public EnumTypeModelBinder(bool allowBindingUndefinedValueToEnumType, Type modelType)
|
||||
public EnumTypeModelBinder(bool supressBindingUndefinedValueToEnumType, Type modelType)
|
||||
: base(modelType)
|
||||
{
|
||||
if (modelType == null)
|
||||
|
|
@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
throw new ArgumentNullException(nameof(modelType));
|
||||
}
|
||||
|
||||
_allowBindingUndefinedValueToEnumType = allowBindingUndefinedValueToEnumType;
|
||||
_suppressBindingUndefinedValueToEnumType = supressBindingUndefinedValueToEnumType;
|
||||
}
|
||||
|
||||
protected override void CheckModel(
|
||||
|
|
@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
ValueProviderResult valueProviderResult,
|
||||
object model)
|
||||
{
|
||||
if (model == null || _allowBindingUndefinedValueToEnumType)
|
||||
if (model == null || !_suppressBindingUndefinedValueToEnumType)
|
||||
{
|
||||
base.CheckModel(bindingContext, valueProviderResult, model);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
if (context.Metadata.IsEnum)
|
||||
{
|
||||
return new EnumTypeModelBinder(
|
||||
_options.AllowBindingUndefinedValueToEnumType,
|
||||
_options.SuppressBindingUndefinedValueToEnumType,
|
||||
context.Metadata.UnderlyingOrModelType);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
private int _maxModelStateErrors = ModelStateDictionary.DefaultMaxAllowedErrors;
|
||||
|
||||
// See CompatibilitySwitch.cs for guide on how to implement these.
|
||||
private readonly CompatibilitySwitch<bool> _allowBindingUndefinedValueToEnumType;
|
||||
private readonly CompatibilitySwitch<InputFormatterExceptionModelStatePolicy> _inputFormatterExceptionModelStatePolicy;
|
||||
private readonly CompatibilitySwitch<bool> _suppressBindingUndefinedValueToEnumType;
|
||||
private readonly CompatibilitySwitch<bool> _suppressJsonDeserializationExceptionMessagesInModelState;
|
||||
private readonly ICompatibilitySwitch[] _switches;
|
||||
|
||||
|
|
@ -41,13 +41,13 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
ModelValidatorProviders = new List<IModelValidatorProvider>();
|
||||
ValueProviderFactories = new List<IValueProviderFactory>();
|
||||
|
||||
_allowBindingUndefinedValueToEnumType = new CompatibilitySwitch<bool>(nameof(AllowBindingUndefinedValueToEnumType));
|
||||
_inputFormatterExceptionModelStatePolicy = new CompatibilitySwitch<InputFormatterExceptionModelStatePolicy>(nameof(InputFormatterExceptionModelStatePolicy), InputFormatterExceptionModelStatePolicy.AllExceptions);
|
||||
_suppressBindingUndefinedValueToEnumType = new CompatibilitySwitch<bool>(nameof(SuppressBindingUndefinedValueToEnumType));
|
||||
_suppressJsonDeserializationExceptionMessagesInModelState = new CompatibilitySwitch<bool>(nameof(SuppressJsonDeserializationExceptionMessagesInModelState));
|
||||
_switches = new ICompatibilitySwitch[]
|
||||
{
|
||||
_allowBindingUndefinedValueToEnumType,
|
||||
_inputFormatterExceptionModelStatePolicy,
|
||||
_suppressBindingUndefinedValueToEnumType,
|
||||
_suppressJsonDeserializationExceptionMessagesInModelState,
|
||||
};
|
||||
}
|
||||
|
|
@ -92,6 +92,35 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// </summary>
|
||||
public FormatterCollection<IInputFormatter> InputFormatters { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an value indicating whether the model binding system will bind undefined values to
|
||||
/// enum types. The default value of the property is <c>false</c>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This property is associated with a compatibility switch and can provide a different behavior depending on
|
||||
/// the configured compatibility version for the application. See <see cref="CompatibilityVersion"/> for
|
||||
/// guidance and examples of setting the application's compatibility version.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Configuring the desired of the value compatibility switch by calling this property's setter will take precedence
|
||||
/// over the value implied by the application's <see cref="CompatibilityVersion"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_0"/> then
|
||||
/// this setting will have value <c>false</c> if not explicitly configured.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_1"/> or
|
||||
/// higher then this setting will have value <c>true</c> if not explicitly configured.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public bool SuppressBindingUndefinedValueToEnumType
|
||||
{
|
||||
get => _suppressBindingUndefinedValueToEnumType.Value;
|
||||
set => _suppressBindingUndefinedValueToEnumType.Value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the flag to buffer the request body in input formatters. Default is <c>false</c>.
|
||||
/// </summary>
|
||||
|
|
@ -181,15 +210,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// </summary>
|
||||
public bool RequireHttpsPermanent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an indication whether the model binding system will bind undefined values to enumeration types.
|
||||
/// <see langword="false"/> by default.
|
||||
/// </summary>
|
||||
public bool AllowBindingUndefinedValueToEnumType
|
||||
{
|
||||
get => _allowBindingUndefinedValueToEnumType.Value;
|
||||
set => _allowBindingUndefinedValueToEnumType.Value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the option to determine if model binding should convert all exceptions (including ones not related to bad input)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
public void ReturnsBinder_ForEnumType(Type modelType)
|
||||
{
|
||||
// Arrange
|
||||
var provider = new EnumTypeModelBinderProvider(new MvcOptions { AllowBindingUndefinedValueToEnumType = true });
|
||||
var provider = new EnumTypeModelBinderProvider(new MvcOptions());
|
||||
var context = new TestModelBinderProviderContext(modelType);
|
||||
|
||||
// Act
|
||||
|
|
@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
public void ReturnsBinder_ForFlagsEnumType(Type modelType)
|
||||
{
|
||||
// Arrange
|
||||
var provider = new EnumTypeModelBinderProvider(new MvcOptions { AllowBindingUndefinedValueToEnumType = true });
|
||||
var provider = new EnumTypeModelBinderProvider(new MvcOptions());
|
||||
var context = new TestModelBinderProviderContext(modelType);
|
||||
|
||||
// Act
|
||||
|
|
@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
public void DoesNotReturnBinder_ForNonEnumTypes(Type modelType)
|
||||
{
|
||||
// Arrange
|
||||
var provider = new EnumTypeModelBinderProvider(new MvcOptions { AllowBindingUndefinedValueToEnumType = false });
|
||||
var provider = new EnumTypeModelBinderProvider(new MvcOptions());
|
||||
var context = new TestModelBinderProviderContext(modelType);
|
||||
|
||||
// Act
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||
|
|
@ -18,13 +17,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
[InlineData(false, typeof(IntEnum?))]
|
||||
[InlineData(false, typeof(FlagsEnum?))]
|
||||
public async Task BindModel_SetsModel_ForEmptyValue_AndNullableEnumTypes(
|
||||
bool allowBindingUndefinedValueToEnumType,
|
||||
bool suppressBindingUndefinedValueToEnumType,
|
||||
Type modelType)
|
||||
{
|
||||
// Arrange
|
||||
var binderInfo = GetBinderAndContext(
|
||||
modelType,
|
||||
allowBindingUndefinedValueToEnumType,
|
||||
suppressBindingUndefinedValueToEnumType,
|
||||
valueProviderValue: "");
|
||||
var bindingContext = binderInfo.Item1;
|
||||
var binder = binderInfo.Item2;
|
||||
|
|
@ -43,14 +42,14 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
[InlineData(false, typeof(IntEnum))]
|
||||
[InlineData(false, typeof(FlagsEnum))]
|
||||
public async Task BindModel_AddsErrorToModelState_ForEmptyValue_AndNonNullableEnumTypes(
|
||||
bool allowBindingUndefinedValueToEnumType,
|
||||
bool suprressBindingUndefinedValueToEnumType,
|
||||
Type modelType)
|
||||
{
|
||||
// Arrange
|
||||
var message = "The value '' is invalid.";
|
||||
var binderInfo = GetBinderAndContext(
|
||||
modelType,
|
||||
allowBindingUndefinedValueToEnumType,
|
||||
suprressBindingUndefinedValueToEnumType,
|
||||
valueProviderValue: "");
|
||||
var bindingContext = binderInfo.Item1;
|
||||
var binder = binderInfo.Item2;
|
||||
|
|
@ -72,14 +71,14 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
[InlineData(false, "Value1")]
|
||||
[InlineData(false, "1")]
|
||||
public async Task BindModel_BindsEnumModels_ForValuesInArray(
|
||||
bool allowBindingUndefinedValueToEnumType,
|
||||
bool suppressBindingUndefinedValueToEnumType,
|
||||
string enumValue)
|
||||
{
|
||||
// Arrange
|
||||
var modelType = typeof(IntEnum);
|
||||
var binderInfo = GetBinderAndContext(
|
||||
modelType,
|
||||
allowBindingUndefinedValueToEnumType,
|
||||
suppressBindingUndefinedValueToEnumType,
|
||||
valueProviderValue: new object[] { enumValue });
|
||||
var bindingContext = binderInfo.Item1;
|
||||
var binder = binderInfo.Item2;
|
||||
|
|
@ -102,7 +101,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
[InlineData("8, 1", false)]
|
||||
[InlineData("Value2, Value8", false)]
|
||||
[InlineData("value8,value4,value2,value1", false)]
|
||||
public async Task BindModel_BindsTo_NonNullableFlagsEnumType(string flagsEnumValue, bool allowBindingUndefinedValueToEnumType)
|
||||
public async Task BindModel_BindsTo_NonNullableFlagsEnumType(string flagsEnumValue, bool suppressBindingUndefinedValueToEnumType)
|
||||
{
|
||||
// Arrange
|
||||
var modelType = typeof(FlagsEnum);
|
||||
|
|
@ -110,7 +109,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
var expected = enumConverter.ConvertFrom(flagsEnumValue).ToString();
|
||||
var binderInfo = GetBinderAndContext(
|
||||
modelType,
|
||||
allowBindingUndefinedValueToEnumType,
|
||||
suppressBindingUndefinedValueToEnumType,
|
||||
valueProviderValue: new object[] { flagsEnumValue });
|
||||
var bindingContext = binderInfo.Item1;
|
||||
var binder = binderInfo.Item2;
|
||||
|
|
@ -133,7 +132,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
[InlineData("8, 1", false)]
|
||||
[InlineData("Value2, Value8", false)]
|
||||
[InlineData("value8,value4,value2,value1", false)]
|
||||
public async Task BindModel_BindsTo_NullableFlagsEnumType(string flagsEnumValue, bool allowBindingUndefinedValueToEnumType)
|
||||
public async Task BindModel_BindsTo_NullableFlagsEnumType(string flagsEnumValue, bool suppressBindingUndefinedValueToEnumType)
|
||||
{
|
||||
// Arrange
|
||||
var modelType = typeof(FlagsEnum?);
|
||||
|
|
@ -141,7 +140,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
var expected = enumConverter.ConvertFrom(flagsEnumValue).ToString();
|
||||
var binderInfo = GetBinderAndContext(
|
||||
modelType,
|
||||
allowBindingUndefinedValueToEnumType,
|
||||
suppressBindingUndefinedValueToEnumType,
|
||||
valueProviderValue: new object[] { flagsEnumValue });
|
||||
var bindingContext = binderInfo.Item1;
|
||||
var binder = binderInfo.Item2;
|
||||
|
|
@ -168,7 +167,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
var message = $"The value '{suppliedValue}' is not valid.";
|
||||
var binderInfo = GetBinderAndContext(
|
||||
modelType,
|
||||
allowBindingUndefinedValueToEnumType: true,
|
||||
suppressBindingUndefinedValueToEnumType: false,
|
||||
valueProviderValue: new object[] { suppliedValue });
|
||||
var bindingContext = binderInfo.Item1;
|
||||
var binder = binderInfo.Item2;
|
||||
|
|
@ -209,7 +208,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
var message = $"The value '{suppliedValue}' is invalid.";
|
||||
var binderInfo = GetBinderAndContext(
|
||||
modelType,
|
||||
allowBindingUndefinedValueToEnumType: false,
|
||||
suppressBindingUndefinedValueToEnumType: true,
|
||||
valueProviderValue: new object[] { suppliedValue });
|
||||
var bindingContext = binderInfo.Item1;
|
||||
var binder = binderInfo.Item2;
|
||||
|
|
@ -251,7 +250,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
var binderProviderContext = new TestModelBinderProviderContext(modelType);
|
||||
var binderInfo = GetBinderAndContext(
|
||||
modelType,
|
||||
allowBindingUndefinedValueToEnumType: true,
|
||||
suppressBindingUndefinedValueToEnumType: false,
|
||||
valueProviderValue: new object[] { suppliedValue });
|
||||
var bindingContext = binderInfo.Item1;
|
||||
var binder = binderInfo.Item2;
|
||||
|
|
@ -267,7 +266,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
|
||||
private static (DefaultModelBindingContext, IModelBinder) GetBinderAndContext(
|
||||
Type modelType,
|
||||
bool allowBindingUndefinedValueToEnumType,
|
||||
bool suppressBindingUndefinedValueToEnumType,
|
||||
object valueProviderValue)
|
||||
{
|
||||
var binderProviderContext = new TestModelBinderProviderContext(modelType);
|
||||
|
|
@ -284,7 +283,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
};
|
||||
var binderProvider = new EnumTypeModelBinderProvider(new MvcOptions
|
||||
{
|
||||
AllowBindingUndefinedValueToEnumType = allowBindingUndefinedValueToEnumType
|
||||
SuppressBindingUndefinedValueToEnumType = suppressBindingUndefinedValueToEnumType
|
||||
});
|
||||
var binder = binderProvider.GetBinder(binderProviderContext);
|
||||
return (bindingContext, binder);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
var mvcOptions = services.GetRequiredService<IOptions<MvcOptions>>().Value;
|
||||
|
||||
// Assert
|
||||
Assert.False(mvcOptions.AllowBindingUndefinedValueToEnumType);
|
||||
Assert.False(mvcOptions.SuppressBindingUndefinedValueToEnumType);
|
||||
Assert.Equal(InputFormatterExceptionModelStatePolicy.AllExceptions, mvcOptions.InputFormatterExceptionModelStatePolicy);
|
||||
Assert.False(mvcOptions.SuppressJsonDeserializationExceptionMessagesInModelState); // This name needs to be inverted in #7157
|
||||
}
|
||||
|
|
@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
var mvcOptions = services.GetRequiredService<IOptions<MvcOptions>>().Value;
|
||||
|
||||
// Assert
|
||||
Assert.True(mvcOptions.AllowBindingUndefinedValueToEnumType);
|
||||
Assert.True(mvcOptions.SuppressBindingUndefinedValueToEnumType);
|
||||
Assert.Equal(InputFormatterExceptionModelStatePolicy.MalformedInputExceptions, mvcOptions.InputFormatterExceptionModelStatePolicy);
|
||||
Assert.True(mvcOptions.SuppressJsonDeserializationExceptionMessagesInModelState); // This name needs to be inverted in #7157
|
||||
}
|
||||
|
|
@ -68,7 +68,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
var mvcOptions = services.GetRequiredService<IOptions<MvcOptions>>().Value;
|
||||
|
||||
// Assert
|
||||
Assert.True(mvcOptions.AllowBindingUndefinedValueToEnumType);
|
||||
Assert.True(mvcOptions.SuppressBindingUndefinedValueToEnumType);
|
||||
Assert.Equal(InputFormatterExceptionModelStatePolicy.MalformedInputExceptions, mvcOptions.InputFormatterExceptionModelStatePolicy);
|
||||
Assert.True(mvcOptions.SuppressJsonDeserializationExceptionMessagesInModelState); // This name needs to be inverted in #7157
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue