Removed use of LINQ and added some optimizations in ValidationVisitor
This commit is contained in:
parent
bebd3dc9a0
commit
f7a211c095
|
|
@ -10,12 +10,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IModelValidator
|
public interface IModelValidator
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether or not this validator validates that a required value
|
|
||||||
/// has been provided for the model.
|
|
||||||
/// </summary>
|
|
||||||
bool IsRequired { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Validates the model value.
|
/// Validates the model value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="ModelBinding.ModelMetadata"/>.
|
/// Gets the <see cref="ModelBinding.ModelMetadata"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ModelMetadata ModelMetadata { get; }
|
public ModelMetadata ModelMetadata { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the validator metadata.
|
/// Gets the validator metadata.
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
|
|
@ -23,6 +22,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
private string _key;
|
private string _key;
|
||||||
private object _model;
|
private object _model;
|
||||||
private ModelMetadata _metadata;
|
private ModelMetadata _metadata;
|
||||||
|
private ModelValidatorProviderContext _context;
|
||||||
private IValidationStrategy _strategy;
|
private IValidationStrategy _strategy;
|
||||||
|
|
||||||
private HashSet<object> _currentPath;
|
private HashSet<object> _currentPath;
|
||||||
|
|
@ -94,7 +94,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
var state = _modelState.GetValidationState(_key);
|
var state = _modelState.GetValidationState(_key);
|
||||||
if (state == ModelValidationState.Unvalidated)
|
if (state == ModelValidationState.Unvalidated)
|
||||||
{
|
{
|
||||||
var validators = GetValidators(_metadata);
|
var validators = GetValidators();
|
||||||
|
|
||||||
var count = validators.Count;
|
var count = validators.Count;
|
||||||
if (count > 0)
|
if (count > 0)
|
||||||
|
|
@ -255,11 +255,23 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
return isValid;
|
return isValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IList<IModelValidator> GetValidators(ModelMetadata metadata)
|
private IList<IModelValidator> GetValidators()
|
||||||
{
|
{
|
||||||
var context = new ModelValidatorProviderContext(metadata);
|
if (_context == null)
|
||||||
_validatorProvider.GetValidators(context);
|
{
|
||||||
return context.Validators.OrderBy(v => v, ValidatorOrderComparer.Instance).ToList();
|
_context = new ModelValidatorProviderContext(_metadata);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Reusing the context so we don't allocate a new context and list
|
||||||
|
// for every property that gets validated.
|
||||||
|
_context.ModelMetadata = _metadata;
|
||||||
|
_context.Validators.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
_validatorProvider.GetValidators(_context);
|
||||||
|
|
||||||
|
return _context.Validators;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SuppressValidation(string key)
|
private void SuppressValidation(string key)
|
||||||
|
|
@ -348,19 +360,5 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
_visitor._currentPath.Remove(_newModel);
|
_visitor._currentPath.Remove(_newModel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sorts validators based on whether or not they are 'required'. We want to run
|
|
||||||
// 'required' validators first so that we get the best possible error message.
|
|
||||||
private class ValidatorOrderComparer : IComparer<IModelValidator>
|
|
||||||
{
|
|
||||||
public static readonly ValidatorOrderComparer Instance = new ValidatorOrderComparer();
|
|
||||||
|
|
||||||
public int Compare(IModelValidator x, IModelValidator y)
|
|
||||||
{
|
|
||||||
var xScore = x.IsRequired ? 0 : 1;
|
|
||||||
var yScore = y.IsRequired ? 0 : 1;
|
|
||||||
return xScore.CompareTo(yScore);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
|
|
||||||
public ValidationAttribute Attribute { get; }
|
public ValidationAttribute Attribute { get; }
|
||||||
|
|
||||||
public bool IsRequired
|
|
||||||
{
|
|
||||||
get { return Attribute is RequiredAttribute; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<ModelValidationResult> Validate(ModelValidationContext validationContext)
|
public IEnumerable<ModelValidationResult> Validate(ModelValidationContext validationContext)
|
||||||
{
|
{
|
||||||
var metadata = validationContext.Metadata;
|
var metadata = validationContext.Metadata;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// 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.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.Extensions.Localization;
|
using Microsoft.Extensions.Localization;
|
||||||
using Microsoft.Extensions.OptionsModel;
|
using Microsoft.Extensions.OptionsModel;
|
||||||
|
|
@ -43,9 +41,26 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
_stringLocalizerFactory);
|
_stringLocalizerFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var attribute in context.ValidatorMetadata.OfType<ValidationAttribute>())
|
for (var i = 0; i < context.ValidatorMetadata.Count; i++)
|
||||||
{
|
{
|
||||||
context.Validators.Add(new DataAnnotationsModelValidator(attribute, stringLocalizer));
|
var attribute = context.ValidatorMetadata[i] as ValidationAttribute;
|
||||||
|
if (attribute == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var validator = new DataAnnotationsModelValidator(attribute, stringLocalizer);
|
||||||
|
|
||||||
|
// Inserts validators based on whether or not they are 'required'. We want to run
|
||||||
|
// 'required' validators first so that we get the best possible error message.
|
||||||
|
if (attribute is RequiredAttribute)
|
||||||
|
{
|
||||||
|
context.Validators.Insert(0, validator);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Validators.Add(validator);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Produce a validator if the type supports IValidatableObject
|
// Produce a validator if the type supports IValidatableObject
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
{
|
{
|
||||||
public class ValidatableObjectAdapter : IModelValidator
|
public class ValidatableObjectAdapter : IModelValidator
|
||||||
{
|
{
|
||||||
public bool IsRequired
|
|
||||||
{
|
|
||||||
get { return false; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
|
public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
|
||||||
{
|
{
|
||||||
var model = context.Model;
|
var model = context.Model;
|
||||||
|
|
|
||||||
|
|
@ -70,14 +70,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
|
|
||||||
private class TestModelValidationAttribute : Attribute, IModelValidator
|
private class TestModelValidationAttribute : Attribute, IModelValidator
|
||||||
{
|
{
|
||||||
public bool IsRequired
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
|
public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|
@ -94,14 +86,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
|
|
||||||
private class TestValidationAttribute : Attribute, IModelValidator, IClientModelValidator
|
private class TestValidationAttribute : Attribute, IModelValidator, IClientModelValidator
|
||||||
{
|
{
|
||||||
public bool IsRequired
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ClientModelValidationContext context)
|
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ClientModelValidationContext context)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|
|
||||||
|
|
@ -171,14 +171,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
{
|
{
|
||||||
public string Tag { get; set; }
|
public string Tag { get; set; }
|
||||||
|
|
||||||
public bool IsRequired
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
|
public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,27 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetValidators_InsertsRequiredValidatorsFirst()
|
||||||
|
{
|
||||||
|
var provider = new DataAnnotationsModelValidatorProvider(
|
||||||
|
new TestOptionsManager<MvcDataAnnotationsLocalizationOptions>(),
|
||||||
|
stringLocalizerFactory: null);
|
||||||
|
var metadata = _metadataProvider.GetMetadataForProperty(
|
||||||
|
typeof(ClassWithProperty),
|
||||||
|
"PropertyWithMultipleValidationAttributes");
|
||||||
|
|
||||||
|
var providerContext = new ModelValidatorProviderContext(metadata);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
provider.GetValidators(providerContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(4, providerContext.Validators.Count);
|
||||||
|
Assert.IsAssignableFrom<RequiredAttribute>(((DataAnnotationsModelValidator)providerContext.Validators[0]).Attribute);
|
||||||
|
Assert.IsAssignableFrom<RequiredAttribute>(((DataAnnotationsModelValidator)providerContext.Validators[1]).Attribute);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void UnknownValidationAttributeGetsDefaultAdapter()
|
public void UnknownValidationAttributeGetsDefaultAdapter()
|
||||||
{
|
{
|
||||||
|
|
@ -130,5 +151,30 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
|
|
||||||
public int WithoutAttribute { get; set; }
|
public int WithoutAttribute { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ClassWithProperty
|
||||||
|
{
|
||||||
|
[CustomNonRequiredAttribute1]
|
||||||
|
[CustomNonRequiredAttribute2]
|
||||||
|
[CustomRequiredAttribute1]
|
||||||
|
[CustomRequiredAttribute2]
|
||||||
|
public string PropertyWithMultipleValidationAttributes { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CustomRequiredAttribute1 : RequiredAttribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CustomRequiredAttribute2 : RequiredAttribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CustomNonRequiredAttribute1 : ValidationAttribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CustomNonRequiredAttribute2 : ValidationAttribute
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -294,17 +294,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void IsRequiredTests()
|
|
||||||
{
|
|
||||||
// Arrange & Act & Assert
|
|
||||||
Assert.False(new DataAnnotationsModelValidator(new RangeAttribute(10, 20), stringLocalizer: null)
|
|
||||||
.IsRequired);
|
|
||||||
Assert.True(new DataAnnotationsModelValidator(new RequiredAttribute(), stringLocalizer: null).IsRequired);
|
|
||||||
Assert.True(new DataAnnotationsModelValidator(new DerivedRequiredAttribute(), stringLocalizer: null)
|
|
||||||
.IsRequired);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class DerivedRequiredAttribute : RequiredAttribute
|
private class DerivedRequiredAttribute : RequiredAttribute
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -218,14 +218,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
{
|
{
|
||||||
public string Tag { get; set; }
|
public string Tag { get; set; }
|
||||||
|
|
||||||
public bool IsRequired
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
|
public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue