Reviving MinLength and MaxLength attribute adapters
This commit is contained in:
parent
b0c7dc9220
commit
2ba8780ee0
|
|
@ -84,7 +84,11 @@
|
|||
<Compile Include="Validation\IModelValidator.cs" />
|
||||
<Compile Include="Validation\IModelValidatorProvider.cs" />
|
||||
<Compile Include="Validation\InvalidModelValidatorProvider.cs" />
|
||||
<Compile Include="Validation\MaxLengthAttributeAdapter.cs" />
|
||||
<Compile Include="Validation\MinLengthAttributeAdapter.cs" />
|
||||
<Compile Include="Validation\ModelClientValidationEqualToRule.cs" />
|
||||
<Compile Include="Validation\ModelClientValidationMaxLengthRule.cs" />
|
||||
<Compile Include="Validation\ModelClientValidationMinLengthRule.cs" />
|
||||
<Compile Include="Validation\ModelClientValidationRegexRule.cs" />
|
||||
<Compile Include="Validation\ModelClientValidationRule.cs" />
|
||||
<Compile Include="Validation\ModelValidatedEventArgs.cs" />
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public class DataAnnotationsModelValidatorProvider : AssociatedValidatorProvider
|
||||
{
|
||||
// A factory for validators based on ValidationAttribute.
|
||||
private delegate IModelValidator DataAnnotationsModelValidationFactory(ValidationAttribute attribute);
|
||||
internal delegate IModelValidator DataAnnotationsModelValidationFactory(ValidationAttribute attribute);
|
||||
|
||||
// A factory for validators based on IValidatableObject
|
||||
private delegate IModelValidator DataAnnotationsValidatableObjectAdapterFactory();
|
||||
|
|
@ -36,6 +36,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
private static readonly DataAnnotationsValidatableObjectAdapterFactory _defaultValidatableFactory =
|
||||
() => new ValidatableObjectAdapter();
|
||||
|
||||
internal Dictionary<Type, DataAnnotationsModelValidationFactory> AttributeFactories
|
||||
{
|
||||
get { return _attributeFactories; }
|
||||
}
|
||||
|
||||
private static bool AddImplicitRequiredAttributeForValueTypes
|
||||
{
|
||||
get { return _addImplicitRequiredAttributeForValueTypes; }
|
||||
|
|
@ -72,6 +77,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
AddValidationAttributeAdapter(dict, typeof(RegularExpressionAttribute),
|
||||
(attribute) => new RegularExpressionAttributeAdapter((RegularExpressionAttribute)attribute));
|
||||
|
||||
AddValidationAttributeAdapter(dict, typeof(MaxLengthAttribute),
|
||||
(attribute) => new MaxLengthAttributeAdapter((MaxLengthAttribute)attribute));
|
||||
|
||||
AddValidationAttributeAdapter(dict, typeof(MinLengthAttribute),
|
||||
(attribute) => new MinLengthAttributeAdapter((MinLengthAttribute)attribute));
|
||||
|
||||
AddValidationAttributeAdapter(dict, typeof(CompareAttribute),
|
||||
(attribute) => new CompareAttributeAdapter((CompareAttribute)attribute));
|
||||
|
||||
AddDataTypeAttributeAdapter(dict, typeof(UrlAttribute), "url");
|
||||
|
||||
return dict;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
public class MaxLengthAttributeAdapter : DataAnnotationsModelValidator<MaxLengthAttribute>
|
||||
{
|
||||
public MaxLengthAttributeAdapter(MaxLengthAttribute attribute)
|
||||
: base(attribute)
|
||||
{
|
||||
}
|
||||
|
||||
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules(
|
||||
[NotNull] ClientModelValidationContext context)
|
||||
{
|
||||
var message = GetErrorMessage(context.ModelMetadata);
|
||||
return new[] { new ModelClientValidationMaxLengthRule(message, Attribute.Length) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
public class MinLengthAttributeAdapter : DataAnnotationsModelValidator<MinLengthAttribute>
|
||||
{
|
||||
public MinLengthAttributeAdapter(MinLengthAttribute attribute)
|
||||
: base(attribute)
|
||||
{
|
||||
}
|
||||
|
||||
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules(
|
||||
[NotNull] ClientModelValidationContext context)
|
||||
{
|
||||
var message = GetErrorMessage(context.ModelMetadata);
|
||||
return new[] { new ModelClientValidationMinLengthRule(message, Attribute.Length) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
public class ModelClientValidationMaxLengthRule : ModelClientValidationRule
|
||||
{
|
||||
private const string MaxLengthValidationType = "maxlength";
|
||||
private const string MaxLengthValidationParameter = "max";
|
||||
|
||||
public ModelClientValidationMaxLengthRule([NotNull] string errorMessage, int maximumLength)
|
||||
: base(MaxLengthValidationType, errorMessage)
|
||||
{
|
||||
ValidationParameters[MaxLengthValidationParameter] = maximumLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
public class ModelClientValidationMinLengthRule : ModelClientValidationRule
|
||||
{
|
||||
private const string MinLengthValidationType = "minlength";
|
||||
private const string MinLengthValidationParameter = "min";
|
||||
|
||||
public ModelClientValidationMinLengthRule([NotNull] string errorMessage, int minimumLength)
|
||||
: base(MinLengthValidationType, errorMessage)
|
||||
{
|
||||
ValidationParameters[MinLengthValidationParameter] = minimumLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
#if NET45
|
||||
|
|
@ -12,6 +13,51 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
private readonly DataAnnotationsModelMetadataProvider _metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||
|
||||
public static IEnumerable<object[]> KnownAdapterTypeData
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new object[] { typeof(RegularExpressionAttribute),
|
||||
new RegularExpressionAttribute("abc"),
|
||||
typeof(RegularExpressionAttributeAdapter), null };
|
||||
|
||||
yield return new object[] { typeof(MaxLengthAttribute),
|
||||
new MaxLengthAttribute(),
|
||||
typeof(MaxLengthAttributeAdapter), null };
|
||||
|
||||
yield return new object[] { typeof(MinLengthAttribute),
|
||||
new MinLengthAttribute(1),
|
||||
typeof(MinLengthAttributeAdapter), null };
|
||||
|
||||
yield return new object[] { typeof(UrlAttribute),
|
||||
new UrlAttribute(),
|
||||
typeof(DataTypeAttributeAdapter), "url" };
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData("KnownAdapterTypeData")]
|
||||
public void AdapterForKnownTypeRegistered(Type attributeType,
|
||||
ValidationAttribute validationAttr,
|
||||
Type expectedAdapterType,
|
||||
string expectedRuleName)
|
||||
{
|
||||
// Arrange
|
||||
var adapters = new DataAnnotationsModelValidatorProvider().AttributeFactories;
|
||||
var adapterFactory = adapters.Single(kvp => kvp.Key == attributeType).Value;
|
||||
|
||||
// Act
|
||||
var adapter = adapterFactory(validationAttr);
|
||||
|
||||
// Assert
|
||||
Assert.IsType(expectedAdapterType, adapter);
|
||||
if (expectedRuleName != null)
|
||||
{
|
||||
var dataTypeAdapter = Assert.IsType<DataTypeAttributeAdapter>(adapter);
|
||||
Assert.Equal(expectedRuleName, dataTypeAdapter.RuleName);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UnknownValidationAttributeGetsDefaultAdapter()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.AspNet.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
public class MaxLengthAttributeAdapterTest
|
||||
{
|
||||
[Fact]
|
||||
[ReplaceCulture]
|
||||
public void ClientRulesWithMaxLengthAttribute()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = provider.GetMetadataForProperty(() => null, typeof(string), "Length");
|
||||
var attribute = new MaxLengthAttribute(10);
|
||||
var adapter = new MaxLengthAttributeAdapter(attribute);
|
||||
var context = new ClientModelValidationContext(metadata, provider);
|
||||
|
||||
// Act
|
||||
var rules = adapter.GetClientValidationRules(context);
|
||||
|
||||
// Assert
|
||||
var rule = Assert.Single(rules);
|
||||
Assert.Equal("maxlength", rule.ValidationType);
|
||||
Assert.Equal(1, rule.ValidationParameters.Count);
|
||||
Assert.Equal(10, rule.ValidationParameters["max"]);
|
||||
Assert.Equal("The field Length must be a string or array type with a maximum length of '10'.", rule.ErrorMessage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[ReplaceCulture]
|
||||
public void ClientRulesWithMaxLengthAttributeAndCustomMessage()
|
||||
{
|
||||
// Arrange
|
||||
var propertyName = "Length";
|
||||
var message = "{0} must be at most {1}";
|
||||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = provider.GetMetadataForProperty(() => null, typeof(string), propertyName);
|
||||
var attribute = new MaxLengthAttribute(5) { ErrorMessage = message };
|
||||
var adapter = new MaxLengthAttributeAdapter(attribute);
|
||||
var context = new ClientModelValidationContext(metadata, provider);
|
||||
|
||||
// Act
|
||||
var rules = adapter.GetClientValidationRules(context);
|
||||
|
||||
// Assert
|
||||
var rule = Assert.Single(rules);
|
||||
Assert.Equal("maxlength", rule.ValidationType);
|
||||
Assert.Equal(1, rule.ValidationParameters.Count);
|
||||
Assert.Equal(5, rule.ValidationParameters["max"]);
|
||||
Assert.Equal("Length must be at most 5", rule.ErrorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.AspNet.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
public class MinLengthAttributeAdapterTest
|
||||
{
|
||||
[Fact]
|
||||
[ReplaceCulture]
|
||||
public void ClientRulesWithMinLengthAttribute()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = provider.GetMetadataForProperty(() => null, typeof(string), "Length");
|
||||
var attribute = new MinLengthAttribute(6);
|
||||
var adapter = new MinLengthAttributeAdapter(attribute);
|
||||
var context = new ClientModelValidationContext(metadata, provider);
|
||||
|
||||
// Act
|
||||
var rules = adapter.GetClientValidationRules(context);
|
||||
|
||||
// Assert
|
||||
var rule = Assert.Single(rules);
|
||||
Assert.Equal("minlength", rule.ValidationType);
|
||||
Assert.Equal(1, rule.ValidationParameters.Count);
|
||||
Assert.Equal(6, rule.ValidationParameters["min"]);
|
||||
Assert.Equal("The field Length must be a string or array type with a minimum length of '6'.", rule.ErrorMessage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[ReplaceCulture]
|
||||
public void ClientRulesWithMinLengthAttributeAndCustomMessage()
|
||||
{
|
||||
// Arrange
|
||||
var propertyName = "Length";
|
||||
var message = "Array must have at least {1} items.";
|
||||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = provider.GetMetadataForProperty(() => null, typeof(string), propertyName);
|
||||
var attribute = new MinLengthAttribute(2) { ErrorMessage = message };
|
||||
var adapter = new MinLengthAttributeAdapter(attribute);
|
||||
var context = new ClientModelValidationContext(metadata, provider);
|
||||
|
||||
// Act
|
||||
var rules = adapter.GetClientValidationRules(context);
|
||||
|
||||
// Assert
|
||||
var rule = Assert.Single(rules);
|
||||
Assert.Equal("minlength", rule.ValidationType);
|
||||
Assert.Equal(1, rule.ValidationParameters.Count);
|
||||
Assert.Equal(2, rule.ValidationParameters["min"]);
|
||||
Assert.Equal("Array must have at least 2 items.", rule.ErrorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue