parent
0d603a38cf
commit
d912f6cd39
|
|
@ -1,60 +0,0 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
|
||||||
{
|
|
||||||
public class CompositeModelValidator : IModelValidator
|
|
||||||
{
|
|
||||||
private readonly IEnumerable<IModelValidator> _validators;
|
|
||||||
|
|
||||||
public CompositeModelValidator(IEnumerable<IModelValidator> validators)
|
|
||||||
{
|
|
||||||
_validators = validators;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsRequired
|
|
||||||
{
|
|
||||||
get { return false; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
|
|
||||||
{
|
|
||||||
var propertiesValid = true;
|
|
||||||
var metadata = context.ModelMetadata;
|
|
||||||
|
|
||||||
foreach (var propertyMetadata in metadata.Properties)
|
|
||||||
{
|
|
||||||
var propertyContext = new ModelValidationContext(context, propertyMetadata);
|
|
||||||
|
|
||||||
foreach (var propertyValidator in _validators)
|
|
||||||
{
|
|
||||||
foreach (var validationResult in propertyValidator.Validate(propertyContext))
|
|
||||||
{
|
|
||||||
propertiesValid = false;
|
|
||||||
yield return CreateSubPropertyResult(propertyMetadata, validationResult);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (propertiesValid)
|
|
||||||
{
|
|
||||||
foreach (var typeValidator in _validators)
|
|
||||||
{
|
|
||||||
foreach (var typeResult in typeValidator.Validate(context))
|
|
||||||
{
|
|
||||||
yield return typeResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ModelValidationResult CreateSubPropertyResult(ModelMetadata propertyMetadata,
|
|
||||||
ModelValidationResult propertyResult)
|
|
||||||
{
|
|
||||||
return new ModelValidationResult(propertyMetadata.PropertyName + '.' + propertyResult.MemberName,
|
|
||||||
propertyResult.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A <see cref="IModelValidator"/> to represent an error. This validator will always throw an exception regardless
|
|
||||||
/// of the actual model value.
|
|
||||||
/// This is used to perform meta-validation - that is to verify the validation attributes make sense.
|
|
||||||
/// </summary>
|
|
||||||
public class ErrorModelValidator : IModelValidator
|
|
||||||
{
|
|
||||||
private readonly string _errorMessage;
|
|
||||||
|
|
||||||
public ErrorModelValidator([NotNull] string errorMessage)
|
|
||||||
{
|
|
||||||
_errorMessage = errorMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsRequired
|
|
||||||
{
|
|
||||||
get { return false; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(_errorMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
|
||||||
{
|
|
||||||
public class InvalidModelValidatorProvider : AssociatedValidatorProvider
|
|
||||||
{
|
|
||||||
protected override IEnumerable<IModelValidator> GetValidators(ModelMetadata metadata,
|
|
||||||
IEnumerable<Attribute> attributes)
|
|
||||||
{
|
|
||||||
if (metadata.ContainerType == null || string.IsNullOrEmpty(metadata.PropertyName))
|
|
||||||
{
|
|
||||||
// Validate that the type's fields and nonpublic properties don't have any validation attributes on
|
|
||||||
// them. Validation only runs against public properties
|
|
||||||
var type = metadata.ModelType;
|
|
||||||
var nonPublicProperties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance);
|
|
||||||
foreach (var nonPublicProperty in nonPublicProperties)
|
|
||||||
{
|
|
||||||
if (nonPublicProperty.GetCustomAttributes(typeof(ValidationAttribute), inherit: true).Any())
|
|
||||||
{
|
|
||||||
var message = Resources.FormatValidationAttributeOnNonPublicProperty(nonPublicProperty.Name,
|
|
||||||
type);
|
|
||||||
yield return new ErrorModelValidator(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
|
|
||||||
var allFields = metadata.ModelType.GetFields(bindingFlags);
|
|
||||||
foreach (var field in allFields)
|
|
||||||
{
|
|
||||||
if (field.GetCustomAttributes(typeof(ValidationAttribute), inherit: true).Any())
|
|
||||||
{
|
|
||||||
var message = Resources.FormatValidationAttributeOnField(field.Name, type);
|
|
||||||
yield return new ErrorModelValidator(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Validate that value-typed properties marked as [Required] are also marked as
|
|
||||||
// [DataMember(IsRequired=true)]. Certain formatters may not recognize a member as required if it's
|
|
||||||
// marked as [Required] but not [DataMember(IsRequired=true)]. This is not a problem for reference
|
|
||||||
// types because [Required] will still cause a model error to be raised after a null value is
|
|
||||||
// deserialized.
|
|
||||||
if (metadata.ModelType.GetTypeInfo().IsValueType &&
|
|
||||||
attributes.Any(attribute => attribute is RequiredAttribute))
|
|
||||||
{
|
|
||||||
if (!DataMemberModelValidatorProvider.IsRequiredDataMember(metadata.ContainerType, attributes))
|
|
||||||
{
|
|
||||||
var message = Resources.FormatMissingDataMemberIsRequired(metadata.PropertyName,
|
|
||||||
metadata.ContainerType);
|
|
||||||
yield return new ErrorModelValidator(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.AspNet.Mvc.Razor.Host;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Razor
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Represents information about an injected property.
|
|
||||||
/// </summary>
|
|
||||||
public class InjectDescriptor
|
|
||||||
{
|
|
||||||
public InjectDescriptor(string typeName, string memberName)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(typeName))
|
|
||||||
{
|
|
||||||
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpy, "typeName");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(memberName))
|
|
||||||
{
|
|
||||||
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpy, "memberName");
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeName = typeName;
|
|
||||||
MemberName = memberName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the type name of the injected property
|
|
||||||
/// </summary>
|
|
||||||
public string TypeName { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the name of the injected property.
|
|
||||||
/// </summary>
|
|
||||||
public string MemberName { get; private set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.AspNet.Testing;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
|
||||||
{
|
|
||||||
public class ErrorModelValidatorTest
|
|
||||||
{
|
|
||||||
private readonly DataAnnotationsModelMetadataProvider _metadataProvider = new DataAnnotationsModelMetadataProvider();
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void ValidateThrowsException()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var validator = new ErrorModelValidator("error");
|
|
||||||
|
|
||||||
// Act and Assert
|
|
||||||
ExceptionAssert.Throws<InvalidOperationException>(() => validator.Validate(null), "error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,98 +0,0 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.Serialization;
|
|
||||||
using Microsoft.AspNet.Testing;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
|
||||||
{
|
|
||||||
public class InvalidModelValidatorProviderTest
|
|
||||||
{
|
|
||||||
private static DataAnnotationsModelMetadataProvider _metadataProvider = new DataAnnotationsModelMetadataProvider();
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void GetValidatorsReturnsNothingForValidModel()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var validatorProvider = new InvalidModelValidatorProvider();
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var validators = validatorProvider.GetValidators(_metadataProvider.GetMetadataForType(null, typeof(ValidModel)));
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Empty(validators);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void GetValidatorsReturnsInvalidModelValidatorsForInvalidModelType()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var name = typeof(InvalidModel).FullName;
|
|
||||||
var validatorProvider = new InvalidModelValidatorProvider();
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var validators = validatorProvider.GetValidators(_metadataProvider.GetMetadataForType(null, typeof(InvalidModel)));
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Equal(2, validators.Count());
|
|
||||||
ExceptionAssert.Throws<InvalidOperationException>(() => validators.ElementAt(0).Validate(null),
|
|
||||||
"Non-public property 'Internal' on type '" + name + "' is attributed with one or more validation attributes. Validation attributes on non-public properties are not supported. Consider using a public property for validation instead.");
|
|
||||||
ExceptionAssert.Throws<InvalidOperationException>(() => validators.ElementAt(1).Validate(null),
|
|
||||||
"Field 'Field' on type '" + name + "' is attributed with one or more validation attributes. Validation attributes on fields are not supported. Consider using a public property for validation instead.");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void GetValidatorsReturnsInvalidModelValidatorsForInvalidModelProperty()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var name = typeof(InvalidModel).FullName;
|
|
||||||
var validatorProvider = new InvalidModelValidatorProvider();
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var validators = validatorProvider.GetValidators(_metadataProvider.GetMetadataForProperty(null, typeof(InvalidModel), "Value"));
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Equal(1, validators.Count());
|
|
||||||
ExceptionAssert.Throws<InvalidOperationException>(() => validators.First().Validate(null),
|
|
||||||
"Property 'Value' on type '" + name + "' is invalid. Value-typed properties marked as [Required] must also be marked with [DataMember(IsRequired=true)] to be recognized as required. Consider attributing the declaring type with [DataContract] and the property with [DataMember(IsRequired=true)].");
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataContract]
|
|
||||||
public class ValidModel
|
|
||||||
{
|
|
||||||
[Required]
|
|
||||||
[DataMember]
|
|
||||||
[StringLength(10)]
|
|
||||||
public string Ref { get; set; }
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
internal string Internal { get; set; }
|
|
||||||
|
|
||||||
[Required]
|
|
||||||
[DataMember(IsRequired = true)]
|
|
||||||
public int Value { get; set; }
|
|
||||||
|
|
||||||
public string Field;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class InvalidModel
|
|
||||||
{
|
|
||||||
[Required]
|
|
||||||
public string Ref { get; set; }
|
|
||||||
|
|
||||||
[StringLength(10)]
|
|
||||||
[RegularExpression("pattern")]
|
|
||||||
internal string Internal { get; set; }
|
|
||||||
|
|
||||||
[Required]
|
|
||||||
public int Value { get; set; }
|
|
||||||
|
|
||||||
[StringLength(10)]
|
|
||||||
public string Field;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue