[Fixes #2192] Remove enumerable types from excluded type in validation
This commit is contained in:
parent
784021cf85
commit
823e9f1516
|
|
@ -19,22 +19,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
{
|
||||
Type[] actualTypes;
|
||||
|
||||
var enumerable = type.ExtractGenericInterface(typeof(IEnumerable<>));
|
||||
if (enumerable == null)
|
||||
if (type.IsGenericType() &&
|
||||
type.GetGenericTypeDefinition() == typeof(KeyValuePair<,>))
|
||||
{
|
||||
actualTypes = new Type[] { type };
|
||||
actualTypes = type.GenericTypeArguments;
|
||||
}
|
||||
else
|
||||
{
|
||||
actualTypes = enumerable.GenericTypeArguments;
|
||||
// The following special case is for IEnumerable<KeyValuePair<K,V>>,
|
||||
// supertype of IDictionary<K,V>, and IReadOnlyDictionary<K,V>.
|
||||
if (actualTypes.Length == 1
|
||||
&& actualTypes[0].IsGenericType()
|
||||
&& actualTypes[0].GetGenericTypeDefinition() == typeof(KeyValuePair<,>))
|
||||
{
|
||||
actualTypes = actualTypes[0].GenericTypeArguments;
|
||||
}
|
||||
actualTypes = new Type[] { type };
|
||||
}
|
||||
|
||||
foreach (var actualType in actualTypes)
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@ using Xunit;
|
|||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||
{
|
||||
public class SimpleTypeExcluceFilterTest
|
||||
public class SimpleTypeExcludeFilterTest
|
||||
{
|
||||
[Theory]
|
||||
[MemberData(nameof(ExcludedTypes))]
|
||||
public void SimpleTypeExcluceFilter_ExcludedTypes(Type type)
|
||||
public void SimpleTypeExcludeFilter_ExcludedTypes(Type type)
|
||||
{
|
||||
// Arrange
|
||||
var filter = new SimpleTypesExcludeFilter();
|
||||
|
|
@ -22,7 +22,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
|
||||
[Theory]
|
||||
[MemberData(nameof(IncludedTypes))]
|
||||
public void SimpleTypeExcluceFilter_IncludedTypes(Type type)
|
||||
public void SimpleTypeExcludeFilter_IncludedTypes(Type type)
|
||||
{
|
||||
// Arrange
|
||||
var filter = new SimpleTypesExcludeFilter();
|
||||
|
|
@ -43,24 +43,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
return new TheoryData<Type>()
|
||||
{
|
||||
// Simple types
|
||||
typeof(int[]),
|
||||
typeof(int),
|
||||
typeof(List<decimal>),
|
||||
typeof(SortedSet<int>),
|
||||
typeof(DateTime),
|
||||
|
||||
// Nullable types
|
||||
typeof(ICollection<string>),
|
||||
typeof(int?[]),
|
||||
typeof(SortedSet<int?>),
|
||||
typeof(HashSet<Uri>),
|
||||
typeof(HashSet<string>),
|
||||
|
||||
// Value types
|
||||
typeof(IList<DateTime>),
|
||||
typeof(int?),
|
||||
|
||||
// KeyValue types
|
||||
typeof(Dictionary<int, string>),
|
||||
typeof(IReadOnlyDictionary<int?, char>)
|
||||
typeof(KeyValuePair<string, string>)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -71,12 +61,27 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
{
|
||||
return new TheoryData<Type>()
|
||||
{
|
||||
// Enumerable types
|
||||
typeof(int[]),
|
||||
typeof(List<decimal>),
|
||||
typeof(SortedSet<int>),
|
||||
typeof(ICollection<string>),
|
||||
typeof(int?[]),
|
||||
typeof(SortedSet<int?>),
|
||||
typeof(HashSet<Uri>),
|
||||
typeof(HashSet<string>),
|
||||
typeof(IList<DateTime>),
|
||||
typeof(Dictionary<int, string>),
|
||||
typeof(IReadOnlyDictionary<int?, char>),
|
||||
|
||||
// Complex types
|
||||
typeof(TestType),
|
||||
typeof(TestType[]),
|
||||
typeof(SortedSet<TestType>),
|
||||
typeof(Dictionary<int, TestType>),
|
||||
typeof(Dictionary<TestType, int>),
|
||||
typeof(Dictionary<TestType, TestType>)
|
||||
typeof(Dictionary<TestType, TestType>),
|
||||
typeof(KeyValuePair<string, TestType>)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -472,19 +472,129 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
validator.Validate(validationContext);
|
||||
|
||||
// Assert
|
||||
Assert.True(validationContext.ModelState.IsValid);
|
||||
var modelState = validationContext.ModelState["serviceProvider.TestService"];
|
||||
Assert.Empty(modelState.Errors);
|
||||
Assert.Equal(modelState.ValidationState, ModelValidationState.Skipped);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new[] { "Foo", "Bar", "Baz" }, typeof(string[]))]
|
||||
[InlineData(new[] { 1, 2, 3 }, typeof(int[]))]
|
||||
[InlineData(new[] { "Foo", "Bar", "Baz" }, typeof(IList<string>))]
|
||||
[InlineData(new[] { "Foo", "Bar", "Baz" }, typeof(HashSet<string>))]
|
||||
[InlineData(new[] { "1/1/14", "2/2/14", "3/3/14" }, typeof(ICollection<DateTime>))]
|
||||
[InlineData(new[] { "Foo", "Bar", "Baz" }, typeof(HashSet<Uri>))]
|
||||
public void EnumerableType_ValidationSuccessful(object model, Type type)
|
||||
{
|
||||
// Arrange
|
||||
var modelStateDictionary = new ModelStateDictionary();
|
||||
modelStateDictionary.Add("items[0]", new ModelState());
|
||||
modelStateDictionary.Add("items[1]", new ModelState());
|
||||
modelStateDictionary.Add("items[2]", new ModelState());
|
||||
|
||||
var testValidationContext = GetModelValidationContext(
|
||||
model,
|
||||
type,
|
||||
"items",
|
||||
excludedTypes: null,
|
||||
modelStateDictionary: modelStateDictionary);
|
||||
|
||||
var excludeTypeFilters = new List<IExcludeTypeValidationFilter>();
|
||||
excludeTypeFilters.Add(new SimpleTypesExcludeFilter());
|
||||
|
||||
var mockValidationExcludeFiltersProvider = new Mock<IValidationExcludeFiltersProvider>();
|
||||
mockValidationExcludeFiltersProvider
|
||||
.SetupGet(o => o.ExcludeFilters)
|
||||
.Returns(excludeTypeFilters);
|
||||
testValidationContext.ExcludeFiltersProvider = mockValidationExcludeFiltersProvider.Object;
|
||||
|
||||
var validationContext = testValidationContext.ModelValidationContext;
|
||||
|
||||
var validator = new DefaultObjectValidator(
|
||||
testValidationContext.ExcludeFiltersProvider,
|
||||
testValidationContext.ModelMetadataProvider);
|
||||
|
||||
// Act
|
||||
validator.Validate(validationContext);
|
||||
|
||||
// Assert
|
||||
Assert.True(validationContext.ModelState.IsValid);
|
||||
var modelState = validationContext.ModelState["items"];
|
||||
Assert.Equal(modelState.ValidationState, ModelValidationState.Valid);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DictionaryType_ValidationSuccessful()
|
||||
{
|
||||
// Arrange
|
||||
var modelStateDictionary = new ModelStateDictionary();
|
||||
modelStateDictionary.Add("items[0].Key", new ModelState());
|
||||
modelStateDictionary.Add("items[0].Value", new ModelState());
|
||||
modelStateDictionary.Add("items[1].Key", new ModelState());
|
||||
modelStateDictionary.Add("items[1].Value", new ModelState());
|
||||
|
||||
var model = new Dictionary<string, string>()
|
||||
{
|
||||
{ "FooKey", "FooValue" },
|
||||
{ "BarKey", "BarValue" }
|
||||
};
|
||||
|
||||
var testValidationContext = GetModelValidationContext(
|
||||
model,
|
||||
typeof(Dictionary<string, string>),
|
||||
"items",
|
||||
excludedTypes: null,
|
||||
modelStateDictionary: modelStateDictionary);
|
||||
|
||||
var excludeTypeFilters = new List<IExcludeTypeValidationFilter>();
|
||||
excludeTypeFilters.Add(new SimpleTypesExcludeFilter());
|
||||
|
||||
var mockValidationExcludeFiltersProvider = new Mock<IValidationExcludeFiltersProvider>();
|
||||
mockValidationExcludeFiltersProvider
|
||||
.SetupGet(o => o.ExcludeFilters)
|
||||
.Returns(excludeTypeFilters);
|
||||
testValidationContext.ExcludeFiltersProvider = mockValidationExcludeFiltersProvider.Object;
|
||||
|
||||
var validationContext = testValidationContext.ModelValidationContext;
|
||||
|
||||
var validator = new DefaultObjectValidator(
|
||||
testValidationContext.ExcludeFiltersProvider,
|
||||
testValidationContext.ModelMetadataProvider);
|
||||
|
||||
// Act
|
||||
validator.Validate(validationContext);
|
||||
|
||||
// Assert
|
||||
Assert.True(validationContext.ModelState.IsValid);
|
||||
var modelState = validationContext.ModelState["items"];
|
||||
Assert.Equal(modelState.ValidationState, ModelValidationState.Valid);
|
||||
modelState = validationContext.ModelState["items[0].Key"];
|
||||
Assert.Equal(modelState.ValidationState, ModelValidationState.Skipped);
|
||||
modelState = validationContext.ModelState["items[0].Value"];
|
||||
Assert.Equal(modelState.ValidationState, ModelValidationState.Skipped);
|
||||
modelState = validationContext.ModelState["items[1].Key"];
|
||||
Assert.Equal(modelState.ValidationState, ModelValidationState.Skipped);
|
||||
modelState = validationContext.ModelState["items[1].Value"];
|
||||
Assert.Equal(modelState.ValidationState, ModelValidationState.Skipped);
|
||||
}
|
||||
|
||||
private TestModelValidationContext GetModelValidationContext(
|
||||
object model,
|
||||
Type type,
|
||||
string key = "",
|
||||
List<Type> excludedTypes = null)
|
||||
{
|
||||
var modelStateDictionary = new ModelStateDictionary();
|
||||
return GetModelValidationContext(model, type, key, excludedTypes, new ModelStateDictionary());
|
||||
}
|
||||
|
||||
private TestModelValidationContext GetModelValidationContext(
|
||||
object model,
|
||||
Type type,
|
||||
string key,
|
||||
List<Type> excludedTypes,
|
||||
ModelStateDictionary modelStateDictionary)
|
||||
{
|
||||
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||
|
||||
var excludedValidationTypesPredicate = new List<IExcludeTypeValidationFilter>();
|
||||
|
|
|
|||
Loading…
Reference in New Issue