[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;
|
Type[] actualTypes;
|
||||||
|
|
||||||
var enumerable = type.ExtractGenericInterface(typeof(IEnumerable<>));
|
if (type.IsGenericType() &&
|
||||||
if (enumerable == null)
|
type.GetGenericTypeDefinition() == typeof(KeyValuePair<,>))
|
||||||
{
|
{
|
||||||
actualTypes = new Type[] { type };
|
actualTypes = type.GenericTypeArguments;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
actualTypes = enumerable.GenericTypeArguments;
|
actualTypes = new Type[] { type };
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var actualType in actualTypes)
|
foreach (var actualType in actualTypes)
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,11 @@ using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
{
|
{
|
||||||
public class SimpleTypeExcluceFilterTest
|
public class SimpleTypeExcludeFilterTest
|
||||||
{
|
{
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(ExcludedTypes))]
|
[MemberData(nameof(ExcludedTypes))]
|
||||||
public void SimpleTypeExcluceFilter_ExcludedTypes(Type type)
|
public void SimpleTypeExcludeFilter_ExcludedTypes(Type type)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var filter = new SimpleTypesExcludeFilter();
|
var filter = new SimpleTypesExcludeFilter();
|
||||||
|
|
@ -22,7 +22,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(IncludedTypes))]
|
[MemberData(nameof(IncludedTypes))]
|
||||||
public void SimpleTypeExcluceFilter_IncludedTypes(Type type)
|
public void SimpleTypeExcludeFilter_IncludedTypes(Type type)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var filter = new SimpleTypesExcludeFilter();
|
var filter = new SimpleTypesExcludeFilter();
|
||||||
|
|
@ -43,24 +43,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
return new TheoryData<Type>()
|
return new TheoryData<Type>()
|
||||||
{
|
{
|
||||||
// Simple types
|
// Simple types
|
||||||
typeof(int[]),
|
|
||||||
typeof(int),
|
typeof(int),
|
||||||
typeof(List<decimal>),
|
typeof(DateTime),
|
||||||
typeof(SortedSet<int>),
|
|
||||||
|
|
||||||
// Nullable types
|
// Nullable types
|
||||||
typeof(ICollection<string>),
|
typeof(int?),
|
||||||
typeof(int?[]),
|
|
||||||
typeof(SortedSet<int?>),
|
|
||||||
typeof(HashSet<Uri>),
|
|
||||||
typeof(HashSet<string>),
|
|
||||||
|
|
||||||
// Value types
|
|
||||||
typeof(IList<DateTime>),
|
|
||||||
|
|
||||||
// KeyValue types
|
// KeyValue types
|
||||||
typeof(Dictionary<int, string>),
|
typeof(KeyValuePair<string, string>)
|
||||||
typeof(IReadOnlyDictionary<int?, char>)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -71,12 +61,27 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
{
|
{
|
||||||
return new TheoryData<Type>()
|
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(TestType[]),
|
typeof(TestType[]),
|
||||||
typeof(SortedSet<TestType>),
|
typeof(SortedSet<TestType>),
|
||||||
typeof(Dictionary<int, TestType>),
|
typeof(Dictionary<int, TestType>),
|
||||||
typeof(Dictionary<TestType, int>),
|
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);
|
validator.Validate(validationContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
Assert.True(validationContext.ModelState.IsValid);
|
||||||
var modelState = validationContext.ModelState["serviceProvider.TestService"];
|
var modelState = validationContext.ModelState["serviceProvider.TestService"];
|
||||||
Assert.Empty(modelState.Errors);
|
Assert.Empty(modelState.Errors);
|
||||||
Assert.Equal(modelState.ValidationState, ModelValidationState.Skipped);
|
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(
|
private TestModelValidationContext GetModelValidationContext(
|
||||||
object model,
|
object model,
|
||||||
Type type,
|
Type type,
|
||||||
string key = "",
|
string key = "",
|
||||||
List<Type> excludedTypes = null)
|
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 modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||||
|
|
||||||
var excludedValidationTypesPredicate = new List<IExcludeTypeValidationFilter>();
|
var excludedValidationTypesPredicate = new List<IExcludeTypeValidationFilter>();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue