Support ModelMetaData.IsRequired
* Update DataAnnotationsModelValidatorProvider to use ModelMetadata.IsRequired * Adding tests and updating existing ones that didn't work with IsRequired Fixes #533
This commit is contained in:
parent
95aa6ad607
commit
7396f58d99
|
|
@ -15,6 +15,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
Display = attributes.OfType<DisplayAttribute>().FirstOrDefault();
|
||||
DisplayFormat = attributes.OfType<DisplayFormatAttribute>().FirstOrDefault();
|
||||
Editable = attributes.OfType<EditableAttribute>().FirstOrDefault();
|
||||
Required = attributes.OfType<RequiredAttribute>().FirstOrDefault();
|
||||
}
|
||||
|
||||
public DisplayAttribute Display { get; protected set; }
|
||||
|
|
@ -22,5 +23,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public DisplayFormatAttribute DisplayFormat { get; protected set; }
|
||||
|
||||
public EditableAttribute Editable { get; protected set; }
|
||||
|
||||
public RequiredAttribute Required { get; protected set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
return base.ComputeIsReadOnly();
|
||||
}
|
||||
|
||||
protected override bool ComputeIsRequired()
|
||||
{
|
||||
return (PrototypeCache.Required != null) || base.ComputeIsRequired();
|
||||
}
|
||||
|
||||
public override string GetDisplayName()
|
||||
{
|
||||
// DisplayAttribute doesn't require you to set a name, so this could be null.
|
||||
|
|
|
|||
|
|
@ -20,12 +20,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
private string _description;
|
||||
private bool _isReadOnly;
|
||||
private bool _isComplexType;
|
||||
private bool _isRequired;
|
||||
|
||||
private bool _convertEmptyStringToNullComputed;
|
||||
private bool _nullDisplayTextComputed;
|
||||
private bool _descriptionComputed;
|
||||
private bool _isReadOnlyComputed;
|
||||
private bool _isComplexTypeComputed;
|
||||
private bool _isRequiredComputed;
|
||||
|
||||
// Constructor for creating real instances of the metadata class based on a prototype
|
||||
protected CachedModelMetadata(CachedModelMetadata<TPrototypeCache> prototype, Func<object> modelAccessor)
|
||||
|
|
@ -125,6 +127,24 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
}
|
||||
|
||||
public sealed override bool IsRequired
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_isRequiredComputed)
|
||||
{
|
||||
_isRequired = ComputeIsRequired();
|
||||
_isRequiredComputed = true;
|
||||
}
|
||||
return _isRequired;
|
||||
}
|
||||
set
|
||||
{
|
||||
_isRequired = value;
|
||||
_isRequiredComputed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed override bool IsComplexType
|
||||
{
|
||||
get
|
||||
|
|
@ -160,6 +180,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
return base.IsReadOnly;
|
||||
}
|
||||
|
||||
protected virtual bool ComputeIsRequired()
|
||||
{
|
||||
return base.IsRequired;
|
||||
}
|
||||
|
||||
protected virtual bool ComputeIsComplexType()
|
||||
{
|
||||
return base.IsComplexType;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
_modelAccessor = modelAccessor;
|
||||
_modelType = modelType;
|
||||
_propertyName = propertyName;
|
||||
IsRequired = !modelType.AllowsNullValue();
|
||||
}
|
||||
|
||||
public Type ContainerType
|
||||
|
|
@ -71,6 +72,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
public virtual bool IsReadOnly { get; set; }
|
||||
|
||||
public virtual bool IsRequired { get; set; }
|
||||
|
||||
public virtual int Order
|
||||
{
|
||||
get { return _order; }
|
||||
|
|
|
|||
|
|
@ -92,6 +92,49 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
Assert.False(new ModelMetadata(provider.Object, null, null, typeof(int), null).IsNullableValueType);
|
||||
}
|
||||
|
||||
// IsRequired
|
||||
|
||||
[Theory]
|
||||
[InlineData(typeof(string))]
|
||||
[InlineData(typeof(IDisposable))]
|
||||
[InlineData(typeof(Nullable<int>))]
|
||||
public void IsRequired_ReturnsFalse_ForNullableTypes(Type modelType)
|
||||
{
|
||||
// Arrange
|
||||
var provider = new Mock<IModelMetadataProvider>();
|
||||
var metadata = new ModelMetadata(provider.Object,
|
||||
containerType: null,
|
||||
modelAccessor: null,
|
||||
modelType: modelType,
|
||||
propertyName: null);
|
||||
|
||||
// Act
|
||||
var isRequired = metadata.IsRequired;
|
||||
|
||||
// Assert
|
||||
Assert.False(isRequired);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(typeof(int))]
|
||||
[InlineData(typeof(DayOfWeek))]
|
||||
public void IsRequired_ReturnsTrue_ForNonNullableTypes(Type modelType)
|
||||
{
|
||||
// Arrange
|
||||
var provider = new Mock<IModelMetadataProvider>();
|
||||
var metadata = new ModelMetadata(provider.Object,
|
||||
containerType: null,
|
||||
modelAccessor: null,
|
||||
modelType: modelType,
|
||||
propertyName: null);
|
||||
|
||||
// Act
|
||||
var isRequired = metadata.IsRequired;
|
||||
|
||||
// Assert
|
||||
Assert.True(isRequired);
|
||||
}
|
||||
|
||||
// Properties
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -16,6 +16,41 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
private readonly DataAnnotationsModelMetadataProvider _metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||
|
||||
[Fact]
|
||||
public void GetValidators_ReturnsValidatorForIValidatableObject()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsModelValidatorProvider();
|
||||
var mockValidatable = Mock.Of<IValidatableObject>();
|
||||
var metadata = _metadataProvider.GetMetadataForType(() => null, mockValidatable.GetType());
|
||||
|
||||
// Act
|
||||
var validators = provider.GetValidators(metadata);
|
||||
|
||||
// Assert
|
||||
var validator = Assert.Single(validators);
|
||||
Assert.IsType<ValidatableObjectAdapter>(validator);
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetValidators_DoesNotAddRequiredAttribute_ForNonNullableValueTypes_IfAttributeIsSpecifiedExplicitly()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsModelValidatorProvider();
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(() => null,
|
||||
typeof(DummyRequiredAttributeHelperClass),
|
||||
"WithAttribute");
|
||||
|
||||
// Act
|
||||
var validators = provider.GetValidators(metadata);
|
||||
|
||||
// Assert
|
||||
var validator = Assert.Single(validators);
|
||||
var adapter = Assert.IsType<RequiredAttributeAdapter>(validator);
|
||||
Assert.Equal("Custom Required Message", adapter.Attribute.ErrorMessage);
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> DataAnnotationAdapters
|
||||
{
|
||||
get
|
||||
|
|
@ -198,5 +233,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
set { base.MyProperty = value; }
|
||||
}
|
||||
}
|
||||
|
||||
private class DummyRequiredAttributeHelperClass
|
||||
{
|
||||
[Required(ErrorMessage = "Custom Required Message")]
|
||||
public int WithAttribute { get; set; }
|
||||
|
||||
public int WithoutAttribute { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue