[Fixes #2192] Remove enumerable types from excluded type in validation

This commit is contained in:
Ajay Bhargav Baaskaran 2015-03-23 11:26:23 -07:00
parent 784021cf85
commit 823e9f1516
3 changed files with 137 additions and 30 deletions

View File

@ -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)

View File

@ -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>)
};
}
}

View File

@ -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>();