Reviving RangeAttributeAdapter, RequiredAttributeAdapter,

StringLengthAttributeAdapter

* Adding remaining DataTypeAttribute adapter rules
This commit is contained in:
Pranav K 2014-04-25 15:54:58 -07:00
parent a5afd3eb42
commit f740aabb79
13 changed files with 300 additions and 23 deletions

View File

@ -71,6 +71,9 @@
<Compile Include="RequestContext.cs" />
<Compile Include="Validation\AssociatedValidatorProvider.cs" />
<Compile Include="Validation\ClientModelValidationContext.cs" />
<Compile Include="Validation\RequiredAttributeAdapter.cs" />
<Compile Include="Validation\StringLengthAttributeAdapter.cs" />
<Compile Include="Validation\RangeAttributeAdapter.cs" />
<Compile Include="Validation\CompareAttributeAdapter.cs" />
<Compile Include="Validation\CompositeModelValidator.cs" />
<Compile Include="Validation\DataAnnotationsModelValidator.cs" />
@ -89,8 +92,11 @@
<Compile Include="Validation\ModelClientValidationEqualToRule.cs" />
<Compile Include="Validation\ModelClientValidationMaxLengthRule.cs" />
<Compile Include="Validation\ModelClientValidationMinLengthRule.cs" />
<Compile Include="Validation\ModelClientValidationRangeRule.cs" />
<Compile Include="Validation\ModelClientValidationRegexRule.cs" />
<Compile Include="Validation\ModelClientValidationRequiredRule.cs" />
<Compile Include="Validation\ModelClientValidationRule.cs" />
<Compile Include="Validation\ModelClientValidationStringLengthRule.cs" />
<Compile Include="Validation\ModelValidatedEventArgs.cs" />
<Compile Include="Validation\ModelValidatingEventArgs.cs" />
<Compile Include="Validation\ModelValidationContext.cs" />

View File

@ -86,6 +86,18 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
AddValidationAttributeAdapter(dict, typeof(CompareAttribute),
(attribute) => new CompareAttributeAdapter((CompareAttribute)attribute));
AddValidationAttributeAdapter(dict, typeof(RequiredAttribute),
(attribute) => new RequiredAttributeAdapter((RequiredAttribute)attribute));
AddValidationAttributeAdapter(dict, typeof(RangeAttribute),
(attribute) => new RangeAttributeAdapter((RangeAttribute)attribute));
AddValidationAttributeAdapter(dict, typeof(StringLengthAttribute),
(attribute) => new StringLengthAttributeAdapter((StringLengthAttribute)attribute));
AddDataTypeAttributeAdapter(dict, typeof(CreditCardAttribute), "creditcard");
AddDataTypeAttributeAdapter(dict, typeof(EmailAddressAttribute), "email");
AddDataTypeAttributeAdapter(dict, typeof(PhoneAttribute), "phone");
AddDataTypeAttributeAdapter(dict, typeof(UrlAttribute), "url");
return dict;

View File

@ -0,0 +1,18 @@
namespace Microsoft.AspNet.Mvc.ModelBinding
{
public class ModelClientValidationRangeRule : ModelClientValidationRule
{
private const string RangeValidationType = "range";
private const string MinValidationParameter = "min";
private const string MaxValidationParameter = "max";
public ModelClientValidationRangeRule([NotNull] string errorMessage,
[NotNull] object minValue,
[NotNull] object maxValue)
: base(RangeValidationType, errorMessage)
{
ValidationParameters[MinValidationParameter] = minValue;
ValidationParameters[MaxValidationParameter] = maxValue;
}
}
}

View File

@ -0,0 +1,12 @@
namespace Microsoft.AspNet.Mvc.ModelBinding
{
public class ModelClientValidationRequiredRule : ModelClientValidationRule
{
private const string RequiredValidationType = "required";
public ModelClientValidationRequiredRule(string errorMessage) :
base(RequiredValidationType, errorMessage)
{
}
}
}

View File

@ -0,0 +1,23 @@
namespace Microsoft.AspNet.Mvc.ModelBinding
{
public class ModelClientValidationStringLengthRule : ModelClientValidationRule
{
private const string LengthValidationType = "length";
private const string MinValidationParameter = "min";
private const string MaxValidationParameter = "max";
public ModelClientValidationStringLengthRule(string errorMessage, int minimumLength, int maximumLength)
: base(LengthValidationType, errorMessage)
{
if (minimumLength != 0)
{
ValidationParameters[MinValidationParameter] = minimumLength;
}
if (maximumLength != int.MaxValue)
{
ValidationParameters[MaxValidationParameter] = maximumLength;
}
}
}
}

View File

@ -0,0 +1,20 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
public class RangeAttributeAdapter : DataAnnotationsModelValidator<RangeAttribute>
{
public RangeAttributeAdapter(RangeAttribute attribute)
: base(attribute)
{
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules(
[NotNull] ClientModelValidationContext context)
{
var errorMessage = GetErrorMessage(context.ModelMetadata);
return new[] { new ModelClientValidationRangeRule(errorMessage, Attribute.Minimum, Attribute.Maximum) };
}
}
}

View File

@ -0,0 +1,20 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
public class RequiredAttributeAdapter : DataAnnotationsModelValidator<RequiredAttribute>
{
public RequiredAttributeAdapter(RequiredAttribute attribute)
: base(attribute)
{
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules(
[NotNull] ClientModelValidationContext context)
{
var errorMessage = GetErrorMessage(context.ModelMetadata);
return new[] { new ModelClientValidationRequiredRule(errorMessage) };
}
}
}

View File

@ -0,0 +1,22 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
public class StringLengthAttributeAdapter : DataAnnotationsModelValidator<StringLengthAttribute>
{
public StringLengthAttributeAdapter(StringLengthAttribute attribute)
: base(attribute)
{
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules(
[NotNull] ClientModelValidationContext context)
{
var errorMessage = GetErrorMessage(context.ModelMetadata);
return new[] { new ModelClientValidationStringLengthRule(errorMessage,
Attribute.MinimumLength,
Attribute.MaximumLength) };
}
}
}

View File

@ -39,6 +39,9 @@
<Compile Include="ModelBindingContextTest.cs" />
<Compile Include="Properties\Resources.Designer.cs" />
<Compile Include="Utils\SimpleHttpValueProvider.cs" />
<Compile Include="Validation\RequiredAttributeAdapterTest.cs" />
<Compile Include="Validation\StringLengthAttributeAdapterTest.cs" />
<Compile Include="Validation\RangeAttributeAdapterTest.cs" />
<Compile Include="Validation\AssociatedValidatorProviderTest.cs" />
<Compile Include="Validation\CompareAttributeTest.cs" />
<Compile Include="Validation\DataAnnotationsModelValidatorProviderTest.cs" />

View File

@ -13,51 +13,74 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{
private readonly DataAnnotationsModelMetadataProvider _metadataProvider = new DataAnnotationsModelMetadataProvider();
public static IEnumerable<object[]> KnownAdapterTypeData
public static IEnumerable<object[]> DataAnnotationAdapters
{
get
{
yield return new object[] { typeof(RegularExpressionAttribute),
new RegularExpressionAttribute("abc"),
typeof(RegularExpressionAttributeAdapter), null };
yield return new object[] { new RegularExpressionAttribute("abc"),
typeof(RegularExpressionAttributeAdapter) };
yield return new object[] { typeof(MaxLengthAttribute),
new MaxLengthAttribute(),
typeof(MaxLengthAttributeAdapter), null };
yield return new object[] { new MaxLengthAttribute(),
typeof(MaxLengthAttributeAdapter) };
yield return new object[] { typeof(MinLengthAttribute),
new MinLengthAttribute(1),
typeof(MinLengthAttributeAdapter), null };
yield return new object[] { new MinLengthAttribute(1),
typeof(MinLengthAttributeAdapter) };
yield return new object[] { typeof(UrlAttribute),
new UrlAttribute(),
typeof(DataTypeAttributeAdapter), "url" };
yield return new object[] { new RangeAttribute(1, 100),
typeof(RangeAttributeAdapter) };
yield return new object[] { new StringLengthAttribute(6),
typeof(StringLengthAttributeAdapter) };
yield return new object[] { new RequiredAttribute(),
typeof(RequiredAttributeAdapter) };
}
}
[Theory]
[MemberData("KnownAdapterTypeData")]
public void AdapterForKnownTypeRegistered(Type attributeType,
ValidationAttribute validationAttr,
Type expectedAdapterType,
string expectedRuleName)
[MemberData("DataAnnotationAdapters")]
public void AdapterFactory_RegistersAdapters_ForDataAnnotationAttributes(ValidationAttribute attribute,
Type expectedAdapterType)
{
// Arrange
var adapters = new DataAnnotationsModelValidatorProvider().AttributeFactories;
var adapterFactory = adapters.Single(kvp => kvp.Key == attributeType).Value;
var adapterFactory = adapters.Single(kvp => kvp.Key == attribute.GetType()).Value;
// Act
var adapter = adapterFactory(validationAttr);
var adapter = adapterFactory(attribute);
// Assert
Assert.IsType(expectedAdapterType, adapter);
if (expectedRuleName != null)
}
public static IEnumerable<object[]> DataTypeAdapters
{
get
{
var dataTypeAdapter = Assert.IsType<DataTypeAttributeAdapter>(adapter);
Assert.Equal(expectedRuleName, dataTypeAdapter.RuleName);
yield return new object[] { new UrlAttribute(), "url" };
yield return new object[] { new CreditCardAttribute(), "creditcard" };
yield return new object[] { new EmailAddressAttribute(), "email" };
yield return new object[] { new PhoneAttribute(), "phone" };
}
}
[Theory]
[MemberData("DataTypeAdapters")]
public void AdapterFactory_RegistersAdapters_ForDataTypeAttributes(ValidationAttribute attribute,
string expectedRuleName)
{
// Arrange
var adapters = new DataAnnotationsModelValidatorProvider().AttributeFactories;
var adapterFactory = adapters.Single(kvp => kvp.Key == attribute.GetType()).Value;
// Act
var adapter = adapterFactory(attribute);
// Assert
var dataTypeAdapter = Assert.IsType<DataTypeAttributeAdapter>(adapter);
Assert.Equal(expectedRuleName, dataTypeAdapter.RuleName);
}
[Fact]
public void UnknownValidationAttributeGetsDefaultAdapter()
{

View File

@ -0,0 +1,32 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNet.Testing;
using Xunit;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
public class RangeAttributeAdapterTest
{
[Fact]
[ReplaceCulture]
public void GetClientValidationRules_ReturnsValidationParameters()
{
// Arrange
var provider = new DataAnnotationsModelMetadataProvider();
var metadata = provider.GetMetadataForProperty(() => null, typeof(string), "Length");
var attribute = new RangeAttribute(typeof(decimal), "0", "100");
var adapter = new RangeAttributeAdapter(attribute);
var context = new ClientModelValidationContext(metadata, provider);
// Act
var rules = adapter.GetClientValidationRules(context);
// Assert
var rule = Assert.Single(rules);
Assert.Equal("range", rule.ValidationType);
Assert.Equal(2, rule.ValidationParameters.Count);
Assert.Equal(0m, rule.ValidationParameters["min"]);
Assert.Equal(100m, rule.ValidationParameters["max"]);
Assert.Equal(@"The field Length must be between 0 and 100.", rule.ErrorMessage);
}
}
}

View File

@ -0,0 +1,30 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNet.Testing;
using Xunit;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
public class RequiredAttributeAdapterTest
{
[Fact]
[ReplaceCulture]
public void GetClientValidationRules_ReturnsValidationParameters()
{
// Arrange
var provider = new DataAnnotationsModelMetadataProvider();
var metadata = provider.GetMetadataForProperty(() => null, typeof(string), "Length");
var attribute = new RequiredAttribute();
var adapter = new RequiredAttributeAdapter(attribute);
var context = new ClientModelValidationContext(metadata, provider);
// Act
var rules = adapter.GetClientValidationRules(context);
// Assert
var rule = Assert.Single(rules);
Assert.Equal("required", rule.ValidationType);
Assert.Empty(rule.ValidationParameters);
Assert.Equal("The Length field is required.", rule.ErrorMessage);
}
}
}

View File

@ -0,0 +1,56 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNet.Testing;
using Xunit;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
public class StringLengthAttributeAdapterTest
{
[Fact]
[ReplaceCulture]
public void GetClientValidationRules_WithMaxLength_ReturnsValidationParameters()
{
// Arrange
var provider = new DataAnnotationsModelMetadataProvider();
var metadata = provider.GetMetadataForProperty(() => null, typeof(string), "Length");
var attribute = new StringLengthAttribute(8);
var adapter = new StringLengthAttributeAdapter(attribute);
var context = new ClientModelValidationContext(metadata, provider);
// Act
var rules = adapter.GetClientValidationRules(context);
// Assert
var rule = Assert.Single(rules);
Assert.Equal("length", rule.ValidationType);
Assert.Equal(1, rule.ValidationParameters.Count);
Assert.Equal(8, rule.ValidationParameters["max"]);
Assert.Equal("The field Length must be a string with a maximum length of 8.",
rule.ErrorMessage);
}
[Fact]
[ReplaceCulture]
public void GetClientValidationRules_WithMinAndMaxLength_ReturnsValidationParameters()
{
// Arrange
var provider = new DataAnnotationsModelMetadataProvider();
var metadata = provider.GetMetadataForProperty(() => null, typeof(string), "Length");
var attribute = new StringLengthAttribute(10) { MinimumLength = 3 };
var adapter = new StringLengthAttributeAdapter(attribute);
var context = new ClientModelValidationContext(metadata, provider);
// Act
var rules = adapter.GetClientValidationRules(context);
// Assert
var rule = Assert.Single(rules);
Assert.Equal("length", rule.ValidationType);
Assert.Equal(2, rule.ValidationParameters.Count);
Assert.Equal(3, rule.ValidationParameters["min"]);
Assert.Equal(10, rule.ValidationParameters["max"]);
Assert.Equal("The field Length must be a string with a minimum length of 3 and a maximum length of 10.",
rule.ErrorMessage);
}
}
}