Added caching for validators
This commit is contained in:
parent
71a815be50
commit
8c4bcf14c7
|
|
@ -13,8 +13,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">The <see cref="ModelValidatorProviderContext"/>.</param>
|
/// <param name="context">The <see cref="ModelValidatorProviderContext"/>.</param>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Implementations should add <see cref="IModelValidator"/> instances to
|
/// Implementations should add the <see cref="IModelValidator"/> instances to the appropriate
|
||||||
/// <see cref="ModelValidatorProviderContext.Validators"/>.
|
/// <see cref="ValidatorItem"/> instance which should be added to
|
||||||
|
/// <see cref="ModelValidatorProviderContext.Results"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
void GetValidators(ModelValidatorProviderContext context);
|
void GetValidators(ModelValidatorProviderContext context);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,11 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
|
||||||
/// Creates a new <see cref="ModelValidatorProviderContext"/>.
|
/// Creates a new <see cref="ModelValidatorProviderContext"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="modelMetadata">The <see cref="ModelBinding.ModelMetadata"/>.</param>
|
/// <param name="modelMetadata">The <see cref="ModelBinding.ModelMetadata"/>.</param>
|
||||||
public ModelValidatorProviderContext(ModelMetadata modelMetadata)
|
/// <param name="items">The list of <see cref="ValidatorItem"/>s.</param>
|
||||||
|
public ModelValidatorProviderContext(ModelMetadata modelMetadata, IList<ValidatorItem> items)
|
||||||
{
|
{
|
||||||
ModelMetadata = modelMetadata;
|
ModelMetadata = modelMetadata;
|
||||||
|
Results = items;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -39,11 +41,11 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the list of <see cref="IModelValidator"/> instances. <see cref="IModelValidatorProvider"/> instances
|
/// Gets the list of <see cref="ValidatorItem"/> instances. <see cref="IModelValidatorProvider"/> instances
|
||||||
/// should add validators to this list when
|
/// should add the appropriate <see cref="ValidatorItem.Validator"/> properties when
|
||||||
/// <see cref="IModelValidatorProvider.GetValidators(ModelValidatorProviderContext)"/>
|
/// <see cref="IModelValidatorProvider.GetValidators(ModelValidatorProviderContext)"/>
|
||||||
/// is called.
|
/// is called.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IList<IModelValidator> Validators { get; } = new List<IModelValidator>();
|
public IList<ValidatorItem> Results { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Used to associate validators with <see cref="ValidatorMetadata"/> instances
|
||||||
|
/// as part of <see cref="ModelValidatorProviderContext"/>. An <see cref="IModelValidator"/> should
|
||||||
|
/// inspect <see cref="ModelValidatorProviderContext.Results"/> and set <see cref="Validator"/> and
|
||||||
|
/// <see cref="IsReusable"/> as appropriate.
|
||||||
|
/// </summary>
|
||||||
|
public class ValidatorItem
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="ValidatorItem"/>.
|
||||||
|
/// </summary>
|
||||||
|
public ValidatorItem()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="ValidatorItem"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="validatorMetadata">The <see cref="ValidatorMetadata"/>.</param>
|
||||||
|
public ValidatorItem(object validatorMetadata)
|
||||||
|
{
|
||||||
|
ValidatorMetadata = validatorMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the metadata associated with the <see cref="Validator"/>.
|
||||||
|
/// </summary>
|
||||||
|
public object ValidatorMetadata { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="IModelValidator"/>.
|
||||||
|
/// </summary>
|
||||||
|
public IModelValidator Validator { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether or not <see cref="Validator"/> can be reused across requests.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsReusable { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -143,6 +143,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
return new DefaultCompositeMetadataDetailsProvider(options.ModelMetadataDetailsProviders);
|
return new DefaultCompositeMetadataDetailsProvider(options.ModelMetadataDetailsProviders);
|
||||||
}));
|
}));
|
||||||
services.TryAddSingleton<IObjectModelValidator, DefaultObjectValidator>();
|
services.TryAddSingleton<IObjectModelValidator, DefaultObjectValidator>();
|
||||||
|
services.TryAddSingleton<ValidatorCache>();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Random Infrastructure
|
// Random Infrastructure
|
||||||
|
|
|
||||||
|
|
@ -153,12 +153,13 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
}
|
}
|
||||||
|
|
||||||
var actionConstraints = new IActionConstraint[count];
|
var actionConstraints = new IActionConstraint[count];
|
||||||
for (int i = 0, j = 0; i < items.Count; i++)
|
var actionConstraintIndex = 0;
|
||||||
|
for (int i = 0; i < items.Count; i++)
|
||||||
{
|
{
|
||||||
var actionConstraint = items[i].Constraint;
|
var actionConstraint = items[i].Constraint;
|
||||||
if (actionConstraint != null)
|
if (actionConstraint != null)
|
||||||
{
|
{
|
||||||
actionConstraints[j++] = actionConstraint;
|
actionConstraints[actionConstraintIndex++] = actionConstraint;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,21 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
public void GetValidators(ModelValidatorProviderContext context)
|
public void GetValidators(ModelValidatorProviderContext context)
|
||||||
{
|
{
|
||||||
//Perf: Avoid allocations here
|
//Perf: Avoid allocations here
|
||||||
for (var i = 0; i < context.ValidatorMetadata.Count; i++)
|
for (var i = 0; i < context.Results.Count; i++)
|
||||||
{
|
{
|
||||||
var validator = context.ValidatorMetadata[i] as IModelValidator;
|
var validatorItem = context.Results[i];
|
||||||
|
|
||||||
|
// Don't overwrite anything that was done by a previous provider.
|
||||||
|
if (validatorItem.Validator != null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var validator = validatorItem.ValidatorMetadata as IModelValidator;
|
||||||
if (validator != null)
|
if (validator != null)
|
||||||
{
|
{
|
||||||
context.Validators.Add(validator);
|
validatorItem.Validator = validator;
|
||||||
|
validatorItem.IsReusable = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,20 +13,28 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
public class DefaultObjectValidator : IObjectModelValidator
|
public class DefaultObjectValidator : IObjectModelValidator
|
||||||
{
|
{
|
||||||
private readonly IModelMetadataProvider _modelMetadataProvider;
|
private readonly IModelMetadataProvider _modelMetadataProvider;
|
||||||
|
private readonly ValidatorCache _validatorCache;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of <see cref="DefaultObjectValidator"/>.
|
/// Initializes a new instance of <see cref="DefaultObjectValidator"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="modelMetadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
|
/// <param name="modelMetadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
|
||||||
public DefaultObjectValidator(
|
public DefaultObjectValidator(
|
||||||
IModelMetadataProvider modelMetadataProvider)
|
IModelMetadataProvider modelMetadataProvider,
|
||||||
|
ValidatorCache validatorCache)
|
||||||
{
|
{
|
||||||
if (modelMetadataProvider == null)
|
if (modelMetadataProvider == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(modelMetadataProvider));
|
throw new ArgumentNullException(nameof(modelMetadataProvider));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (validatorCache == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(validatorCache));
|
||||||
|
}
|
||||||
|
|
||||||
_modelMetadataProvider = modelMetadataProvider;
|
_modelMetadataProvider = modelMetadataProvider;
|
||||||
|
_validatorCache = validatorCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -50,6 +58,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
var visitor = new ValidationVisitor(
|
var visitor = new ValidationVisitor(
|
||||||
actionContext,
|
actionContext,
|
||||||
validatorProvider,
|
validatorProvider,
|
||||||
|
_validatorCache,
|
||||||
_modelMetadataProvider,
|
_modelMetadataProvider,
|
||||||
validationState);
|
validationState);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -151,12 +151,13 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var filters = new IFilterMetadata[count];
|
var filters = new IFilterMetadata[count];
|
||||||
for (int i = 0, j = 0; i < items.Count; i++)
|
var filterIndex = 0;
|
||||||
|
for (int i = 0; i < items.Count; i++)
|
||||||
{
|
{
|
||||||
var filter = items[i].Filter;
|
var filter = items[i].Filter;
|
||||||
if (filter != null)
|
if (filter != null)
|
||||||
{
|
{
|
||||||
filters[j++] = filter;
|
filters[filterIndex++] = filter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,145 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
|
{
|
||||||
|
public class ValidatorCache
|
||||||
|
{
|
||||||
|
private readonly IReadOnlyList<IModelValidator> EmptyArray = new IModelValidator[0];
|
||||||
|
|
||||||
|
private readonly ConcurrentDictionary<ModelMetadata, CacheEntry> _cacheEntries = new ConcurrentDictionary<ModelMetadata, CacheEntry>();
|
||||||
|
|
||||||
|
public IReadOnlyList<IModelValidator> GetValidators(ModelMetadata metadata, IModelValidatorProvider validatorProvider)
|
||||||
|
{
|
||||||
|
CacheEntry entry;
|
||||||
|
if (_cacheEntries.TryGetValue(metadata, out entry))
|
||||||
|
{
|
||||||
|
return GetValidatorsFromEntry(entry, metadata, validatorProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
var items = new List<ValidatorItem>(metadata.ValidatorMetadata.Count);
|
||||||
|
for (var i = 0; i < metadata.ValidatorMetadata.Count; i++)
|
||||||
|
{
|
||||||
|
items.Add(new ValidatorItem(metadata.ValidatorMetadata[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
ExecuteProvider(validatorProvider, metadata, items);
|
||||||
|
|
||||||
|
var validators = ExtractValidators(items);
|
||||||
|
|
||||||
|
var allValidatorsCached = true;
|
||||||
|
for (var i = 0; i < items.Count; i++)
|
||||||
|
{
|
||||||
|
var item = items[i];
|
||||||
|
if (!item.IsReusable)
|
||||||
|
{
|
||||||
|
item.Validator = null;
|
||||||
|
allValidatorsCached = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allValidatorsCached)
|
||||||
|
{
|
||||||
|
entry = new CacheEntry(validators);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entry = new CacheEntry(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
_cacheEntries.TryAdd(metadata, entry);
|
||||||
|
|
||||||
|
return validators;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IReadOnlyList<IModelValidator> GetValidatorsFromEntry(CacheEntry entry, ModelMetadata metadata, IModelValidatorProvider validationProvider)
|
||||||
|
{
|
||||||
|
Debug.Assert(entry.Validators != null || entry.Items != null);
|
||||||
|
|
||||||
|
if (entry.Validators != null)
|
||||||
|
{
|
||||||
|
return entry.Validators;
|
||||||
|
}
|
||||||
|
|
||||||
|
var items = new List<ValidatorItem>(entry.Items.Count);
|
||||||
|
for (var i = 0; i < entry.Items.Count; i++)
|
||||||
|
{
|
||||||
|
var item = entry.Items[i];
|
||||||
|
if (item.IsReusable)
|
||||||
|
{
|
||||||
|
items.Add(item);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
items.Add(new ValidatorItem(item.ValidatorMetadata));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExecuteProvider(validationProvider, metadata, items);
|
||||||
|
|
||||||
|
return ExtractValidators(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExecuteProvider(IModelValidatorProvider validatorProvider, ModelMetadata metadata, List<ValidatorItem> items)
|
||||||
|
{
|
||||||
|
var context = new ModelValidatorProviderContext(metadata, items);
|
||||||
|
validatorProvider.GetValidators(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IReadOnlyList<IModelValidator> ExtractValidators(List<ValidatorItem> items)
|
||||||
|
{
|
||||||
|
var count = 0;
|
||||||
|
for (var i = 0; i < items.Count; i++)
|
||||||
|
{
|
||||||
|
if (items[i].Validator != null)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
return EmptyArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
var validators = new IModelValidator[count];
|
||||||
|
|
||||||
|
var validatorIndex = 0;
|
||||||
|
for (int i = 0; i < items.Count; i++)
|
||||||
|
{
|
||||||
|
var validator = items[i].Validator;
|
||||||
|
if (validator != null)
|
||||||
|
{
|
||||||
|
validators[validatorIndex++] = validator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return validators;
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct CacheEntry
|
||||||
|
{
|
||||||
|
public CacheEntry(IReadOnlyList<IModelValidator> validators)
|
||||||
|
{
|
||||||
|
Validators = validators;
|
||||||
|
Items = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CacheEntry(List<ValidatorItem> items)
|
||||||
|
{
|
||||||
|
Items = items;
|
||||||
|
Validators = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<IModelValidator> Validators { get; }
|
||||||
|
|
||||||
|
public List<ValidatorItem> Items { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,6 +16,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
|
||||||
{
|
{
|
||||||
private readonly IModelValidatorProvider _validatorProvider;
|
private readonly IModelValidatorProvider _validatorProvider;
|
||||||
private readonly IModelMetadataProvider _metadataProvider;
|
private readonly IModelMetadataProvider _metadataProvider;
|
||||||
|
private readonly ValidatorCache _validatorCache;
|
||||||
private readonly ActionContext _actionContext;
|
private readonly ActionContext _actionContext;
|
||||||
private readonly ModelStateDictionary _modelState;
|
private readonly ModelStateDictionary _modelState;
|
||||||
private readonly ValidationStateDictionary _validationState;
|
private readonly ValidationStateDictionary _validationState;
|
||||||
|
|
@ -24,7 +25,6 @@ namespace Microsoft.AspNetCore.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;
|
||||||
|
|
@ -38,6 +38,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
|
||||||
public ValidationVisitor(
|
public ValidationVisitor(
|
||||||
ActionContext actionContext,
|
ActionContext actionContext,
|
||||||
IModelValidatorProvider validatorProvider,
|
IModelValidatorProvider validatorProvider,
|
||||||
|
ValidatorCache validatorCache,
|
||||||
IModelMetadataProvider metadataProvider,
|
IModelMetadataProvider metadataProvider,
|
||||||
ValidationStateDictionary validationState)
|
ValidationStateDictionary validationState)
|
||||||
{
|
{
|
||||||
|
|
@ -51,8 +52,15 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
|
||||||
throw new ArgumentNullException(nameof(validatorProvider));
|
throw new ArgumentNullException(nameof(validatorProvider));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (validatorCache == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(validatorCache));
|
||||||
|
}
|
||||||
|
|
||||||
_actionContext = actionContext;
|
_actionContext = actionContext;
|
||||||
_validatorProvider = validatorProvider;
|
_validatorProvider = validatorProvider;
|
||||||
|
_validatorCache = validatorCache;
|
||||||
|
|
||||||
_metadataProvider = metadataProvider;
|
_metadataProvider = metadataProvider;
|
||||||
_validationState = validationState;
|
_validationState = validationState;
|
||||||
|
|
||||||
|
|
@ -91,7 +99,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
|
||||||
var state = _modelState.GetValidationState(_key);
|
var state = _modelState.GetValidationState(_key);
|
||||||
if (state == ModelValidationState.Unvalidated)
|
if (state == ModelValidationState.Unvalidated)
|
||||||
{
|
{
|
||||||
var validators = GetValidators();
|
var validators = _validatorCache.GetValidators(_metadata, _validatorProvider);
|
||||||
|
|
||||||
var count = validators.Count;
|
var count = validators.Count;
|
||||||
if (count > 0)
|
if (count > 0)
|
||||||
|
|
@ -261,25 +269,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
|
||||||
return isValid;
|
return isValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IList<IModelValidator> GetValidators()
|
|
||||||
{
|
|
||||||
if (_context == null)
|
|
||||||
{
|
|
||||||
_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)
|
||||||
{
|
{
|
||||||
var entries = _modelState.FindKeysWithPrefix(key);
|
var entries = _modelState.FindKeysWithPrefix(key);
|
||||||
|
|
|
||||||
|
|
@ -59,9 +59,15 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
||||||
_stringLocalizerFactory);
|
_stringLocalizerFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < context.ValidatorMetadata.Count; i++)
|
for (var i = 0; i < context.Results.Count; i++)
|
||||||
{
|
{
|
||||||
var attribute = context.ValidatorMetadata[i] as ValidationAttribute;
|
var validatorItem = context.Results[i];
|
||||||
|
if (validatorItem.Validator != null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var attribute = validatorItem.ValidatorMetadata as ValidationAttribute;
|
||||||
if (attribute == null)
|
if (attribute == null)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -72,22 +78,25 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
||||||
attribute,
|
attribute,
|
||||||
stringLocalizer);
|
stringLocalizer);
|
||||||
|
|
||||||
|
validatorItem.Validator = validator;
|
||||||
|
validatorItem.IsReusable = true;
|
||||||
// Inserts validators based on whether or not they are 'required'. We want to run
|
// 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.
|
// 'required' validators first so that we get the best possible error message.
|
||||||
if (attribute is RequiredAttribute)
|
if (attribute is RequiredAttribute)
|
||||||
{
|
{
|
||||||
context.Validators.Insert(0, validator);
|
context.Results.Remove(validatorItem);
|
||||||
}
|
context.Results.Insert(0, validatorItem);
|
||||||
else
|
|
||||||
{
|
|
||||||
context.Validators.Add(validator);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Produce a validator if the type supports IValidatableObject
|
// Produce a validator if the type supports IValidatableObject
|
||||||
if (typeof(IValidatableObject).IsAssignableFrom(context.ModelMetadata.ModelType))
|
if (typeof(IValidatableObject).IsAssignableFrom(context.ModelMetadata.ModelType))
|
||||||
{
|
{
|
||||||
context.Validators.Add(new ValidatableObjectAdapter());
|
context.Results.Add(new ValidatorItem
|
||||||
|
{
|
||||||
|
Validator = new ValidatableObjectAdapter(),
|
||||||
|
IsReusable = true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1542,14 +1542,15 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
||||||
new ModelValidationResult(string.Empty, "Out of range!")
|
new ModelValidationResult(string.Empty, "Out of range!")
|
||||||
};
|
};
|
||||||
|
|
||||||
var validator1 = new Mock<IModelValidator>();
|
var validator = new Mock<IModelValidator>();
|
||||||
|
validator.Setup(v => v.Validate(It.IsAny<ModelValidationContext>()))
|
||||||
validator1.Setup(v => v.Validate(It.IsAny<ModelValidationContext>()))
|
.Returns(validationResult);
|
||||||
.Returns(validationResult);
|
var validator1 = new ValidatorItem(validator.Object);
|
||||||
|
validator1.Validator = validator.Object;
|
||||||
|
|
||||||
var provider = new Mock<IModelValidatorProvider>();
|
var provider = new Mock<IModelValidatorProvider>();
|
||||||
provider.Setup(v => v.GetValidators(It.IsAny<ModelValidatorProviderContext>()))
|
provider.Setup(v => v.GetValidators(It.IsAny<ModelValidatorProviderContext>()))
|
||||||
.Callback<ModelValidatorProviderContext>(c => c.Validators.Add(validator1.Object));
|
.Callback<ModelValidatorProviderContext>(c => c.Results.Add(validator1));
|
||||||
|
|
||||||
var binder = new Mock<IModelBinder>();
|
var binder = new Mock<IModelBinder>();
|
||||||
var controller = GetController(binder.Object, valueProvider: null);
|
var controller = GetController(binder.Object, valueProvider: null);
|
||||||
|
|
@ -1578,14 +1579,15 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
||||||
new ModelValidationResult(string.Empty, "Out of range!")
|
new ModelValidationResult(string.Empty, "Out of range!")
|
||||||
};
|
};
|
||||||
|
|
||||||
var validator1 = new Mock<IModelValidator>();
|
var validator = new Mock<IModelValidator>();
|
||||||
|
validator.Setup(v => v.Validate(It.IsAny<ModelValidationContext>()))
|
||||||
validator1.Setup(v => v.Validate(It.IsAny<ModelValidationContext>()))
|
.Returns(validationResult);
|
||||||
.Returns(validationResult);
|
var validator1 = new ValidatorItem(validator.Object);
|
||||||
|
validator1.Validator = validator.Object;
|
||||||
|
|
||||||
var provider = new Mock<IModelValidatorProvider>();
|
var provider = new Mock<IModelValidatorProvider>();
|
||||||
provider.Setup(v => v.GetValidators(It.IsAny<ModelValidatorProviderContext>()))
|
provider.Setup(v => v.GetValidators(It.IsAny<ModelValidatorProviderContext>()))
|
||||||
.Callback<ModelValidatorProviderContext>(c => c.Validators.Add(validator1.Object));
|
.Callback<ModelValidatorProviderContext>(c => c.Results.Add(validator1));
|
||||||
|
|
||||||
var binder = new Mock<IModelBinder>();
|
var binder = new Mock<IModelBinder>();
|
||||||
var controller = GetController(binder.Object, valueProvider: null);
|
var controller = GetController(binder.Object, valueProvider: null);
|
||||||
|
|
@ -1643,7 +1645,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
||||||
{
|
{
|
||||||
ControllerContext = controllerContext,
|
ControllerContext = controllerContext,
|
||||||
MetadataProvider = metadataProvider,
|
MetadataProvider = metadataProvider,
|
||||||
ObjectValidator = new DefaultObjectValidator(metadataProvider),
|
ObjectValidator = new DefaultObjectValidator(metadataProvider, new ValidatorCache()),
|
||||||
};
|
};
|
||||||
|
|
||||||
return controller;
|
return controller;
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ namespace Microsoft.AspNetCore.Mvc.Controllers
|
||||||
services.Setup(s => s.GetService(typeof(IModelMetadataProvider)))
|
services.Setup(s => s.GetService(typeof(IModelMetadataProvider)))
|
||||||
.Returns(metadataProvider);
|
.Returns(metadataProvider);
|
||||||
services.Setup(s => s.GetService(typeof(IObjectModelValidator)))
|
services.Setup(s => s.GetService(typeof(IObjectModelValidator)))
|
||||||
.Returns(new DefaultObjectValidator(metadataProvider));
|
.Returns(new DefaultObjectValidator(metadataProvider, new ValidatorCache()));
|
||||||
return services.Object;
|
return services.Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -211,7 +211,7 @@ namespace Microsoft.AspNetCore.Mvc.Controllers
|
||||||
services.Setup(s => s.GetService(typeof(IModelMetadataProvider)))
|
services.Setup(s => s.GetService(typeof(IModelMetadataProvider)))
|
||||||
.Returns(metadataProvider);
|
.Returns(metadataProvider);
|
||||||
services.Setup(s => s.GetService(typeof(IObjectModelValidator)))
|
services.Setup(s => s.GetService(typeof(IObjectModelValidator)))
|
||||||
.Returns(new DefaultObjectValidator(metadataProvider));
|
.Returns(new DefaultObjectValidator(metadataProvider, new ValidatorCache()));
|
||||||
return services.Object;
|
return services.Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ using System;
|
||||||
using Microsoft.AspNetCore.Http.Internal;
|
using Microsoft.AspNetCore.Http.Internal;
|
||||||
using Microsoft.AspNetCore.Mvc.ActionConstraints;
|
using Microsoft.AspNetCore.Mvc.ActionConstraints;
|
||||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2114,7 +2114,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
new IInputFormatter[0],
|
new IInputFormatter[0],
|
||||||
new ControllerArgumentBinder(
|
new ControllerArgumentBinder(
|
||||||
metadataProvider,
|
metadataProvider,
|
||||||
new DefaultObjectValidator(metadataProvider)),
|
new DefaultObjectValidator(metadataProvider, new ValidatorCache())),
|
||||||
new IModelBinder[] { binder.Object },
|
new IModelBinder[] { binder.Object },
|
||||||
new IModelValidatorProvider[0],
|
new IModelValidatorProvider[0],
|
||||||
new IValueProviderFactory[0],
|
new IValueProviderFactory[0],
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
using Microsoft.AspNetCore.Mvc.DataAnnotations.Internal;
|
using Microsoft.AspNetCore.Mvc.DataAnnotations.Internal;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
|
|
@ -22,16 +23,16 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
var validatorProvider = TestModelValidatorProvider.CreateDefaultProvider();
|
var validatorProvider = TestModelValidatorProvider.CreateDefaultProvider();
|
||||||
|
|
||||||
var metadata = metadataProvider.GetMetadataForType(typeof(ValidatableObject));
|
var metadata = metadataProvider.GetMetadataForType(typeof(ValidatableObject));
|
||||||
var context = new ModelValidatorProviderContext(metadata);
|
var context = new ModelValidatorProviderContext(metadata, GetValidatorItems(metadata));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
validatorProvider.GetValidators(context);
|
validatorProvider.GetValidators(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var validators = context.Validators;
|
var validatorItems = context.Results;
|
||||||
|
|
||||||
var validator = Assert.Single(validators);
|
var validatorItem = Assert.Single(validatorItems);
|
||||||
Assert.IsType<ValidatableObjectAdapter>(validator);
|
Assert.IsType<ValidatableObjectAdapter>(validatorItem.Validator);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -42,15 +43,15 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
var validatorProvider = TestModelValidatorProvider.CreateDefaultProvider();
|
var validatorProvider = TestModelValidatorProvider.CreateDefaultProvider();
|
||||||
|
|
||||||
var metadata = metadataProvider.GetMetadataForType(typeof(ModelValidatorAttributeOnClass));
|
var metadata = metadataProvider.GetMetadataForType(typeof(ModelValidatorAttributeOnClass));
|
||||||
var context = new ModelValidatorProviderContext(metadata);
|
var context = new ModelValidatorProviderContext(metadata, GetValidatorItems(metadata));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
validatorProvider.GetValidators(context);
|
validatorProvider.GetValidators(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var validators = context.Validators;
|
var validatorItems = context.Results;
|
||||||
|
|
||||||
var validator = Assert.IsType<CustomModelValidatorAttribute>(Assert.Single(validators));
|
var validator = Assert.IsType<CustomModelValidatorAttribute>(Assert.Single(validatorItems).Validator);
|
||||||
Assert.Equal("Class", validator.Tag);
|
Assert.Equal("Class", validator.Tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,15 +65,15 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
var metadata = metadataProvider.GetMetadataForProperty(
|
var metadata = metadataProvider.GetMetadataForProperty(
|
||||||
typeof(ModelValidatorAttributeOnProperty),
|
typeof(ModelValidatorAttributeOnProperty),
|
||||||
nameof(ModelValidatorAttributeOnProperty.Property));
|
nameof(ModelValidatorAttributeOnProperty.Property));
|
||||||
var context = new ModelValidatorProviderContext(metadata);
|
var context = new ModelValidatorProviderContext(metadata, GetValidatorItems(metadata));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
validatorProvider.GetValidators(context);
|
validatorProvider.GetValidators(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var validators = context.Validators;
|
var validatorItems = context.Results;
|
||||||
|
|
||||||
var validator = Assert.IsType<CustomModelValidatorAttribute>(Assert.Single(validators));
|
var validator = Assert.IsType<CustomModelValidatorAttribute>(Assert.Single(validatorItems).Validator);
|
||||||
Assert.Equal("Property", validator.Tag);
|
Assert.Equal("Property", validator.Tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,17 +87,17 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
var metadata = metadataProvider.GetMetadataForProperty(
|
var metadata = metadataProvider.GetMetadataForProperty(
|
||||||
typeof(ModelValidatorAttributeOnPropertyAndClass),
|
typeof(ModelValidatorAttributeOnPropertyAndClass),
|
||||||
nameof(ModelValidatorAttributeOnPropertyAndClass.Property));
|
nameof(ModelValidatorAttributeOnPropertyAndClass.Property));
|
||||||
var context = new ModelValidatorProviderContext(metadata);
|
var context = new ModelValidatorProviderContext(metadata, GetValidatorItems(metadata));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
validatorProvider.GetValidators(context);
|
validatorProvider.GetValidators(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var validators = context.Validators;
|
var validatorItems = context.Results;
|
||||||
|
|
||||||
Assert.Equal(2, validators.Count);
|
Assert.Equal(2, validatorItems.Count);
|
||||||
Assert.Single(validators, v => Assert.IsType<CustomModelValidatorAttribute>(v).Tag == "Class");
|
Assert.Single(validatorItems, v => Assert.IsType<CustomModelValidatorAttribute>(v.Validator).Tag == "Class");
|
||||||
Assert.Single(validators, v => Assert.IsType<CustomModelValidatorAttribute>(v).Tag == "Property");
|
Assert.Single(validatorItems, v => Assert.IsType<CustomModelValidatorAttribute>(v.Validator).Tag == "Property");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -109,15 +110,15 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
var metadata = metadataProvider.GetMetadataForProperty(
|
var metadata = metadataProvider.GetMetadataForProperty(
|
||||||
typeof(ProductViewModel),
|
typeof(ProductViewModel),
|
||||||
nameof(ProductViewModel.Id));
|
nameof(ProductViewModel.Id));
|
||||||
var context = new ModelValidatorProviderContext(metadata);
|
var context = new ModelValidatorProviderContext(metadata, GetValidatorItems(metadata));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
validatorProvider.GetValidators(context);
|
validatorProvider.GetValidators(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var validators = context.Validators;
|
var validatorItems = context.Results;
|
||||||
|
|
||||||
var adapter = Assert.IsType<DataAnnotationsModelValidator>(Assert.Single(validators));
|
var adapter = Assert.IsType<DataAnnotationsModelValidator>(Assert.Single(validatorItems).Validator);
|
||||||
Assert.IsType<RangeAttribute>(adapter.Attribute);
|
Assert.IsType<RangeAttribute>(adapter.Attribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,17 +132,22 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
var metadata = metadataProvider.GetMetadataForProperty(
|
var metadata = metadataProvider.GetMetadataForProperty(
|
||||||
typeof(ProductViewModel),
|
typeof(ProductViewModel),
|
||||||
nameof(ProductViewModel.Name));
|
nameof(ProductViewModel.Name));
|
||||||
var context = new ModelValidatorProviderContext(metadata);
|
var context = new ModelValidatorProviderContext(metadata, GetValidatorItems(metadata));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
validatorProvider.GetValidators(context);
|
validatorProvider.GetValidators(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var validators = context.Validators;
|
var validatorItems = context.Results;
|
||||||
|
|
||||||
Assert.Equal(2, validators.Count);
|
Assert.Equal(2, validatorItems.Count);
|
||||||
Assert.Single(validators, v => ((DataAnnotationsModelValidator)v).Attribute is RegularExpressionAttribute);
|
Assert.Single(validatorItems, v => ((DataAnnotationsModelValidator)v.Validator).Attribute is RegularExpressionAttribute);
|
||||||
Assert.Single(validators, v => ((DataAnnotationsModelValidator)v).Attribute is StringLengthAttribute);
|
Assert.Single(validatorItems, v => ((DataAnnotationsModelValidator)v.Validator).Attribute is StringLengthAttribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IList<ValidatorItem> GetValidatorItems(ModelMetadata metadata)
|
||||||
|
{
|
||||||
|
return metadata.ValidatorMetadata.Select(v => new ValidatorItem(v)).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ValidatableObject : IValidatableObject
|
private class ValidatableObject : IValidatableObject
|
||||||
|
|
@ -157,7 +163,6 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private class ModelValidatorAttributeOnProperty
|
private class ModelValidatorAttributeOnProperty
|
||||||
{
|
{
|
||||||
[CustomModelValidator(Tag = "Property")]
|
[CustomModelValidator(Tag = "Property")]
|
||||||
|
|
|
||||||
|
|
@ -1010,13 +1010,13 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
}
|
}
|
||||||
|
|
||||||
var provider = TestModelMetadataProvider.CreateDefaultProvider(excludeFilters.ToArray());
|
var provider = TestModelMetadataProvider.CreateDefaultProvider(excludeFilters.ToArray());
|
||||||
return new DefaultObjectValidator(provider);
|
return new DefaultObjectValidator(provider, new ValidatorCache());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DefaultObjectValidator CreateValidator(params IMetadataDetailsProvider[] providers)
|
private static DefaultObjectValidator CreateValidator(params IMetadataDetailsProvider[] providers)
|
||||||
{
|
{
|
||||||
var provider = TestModelMetadataProvider.CreateDefaultProvider(providers);
|
var provider = TestModelMetadataProvider.CreateDefaultProvider(providers);
|
||||||
return new DefaultObjectValidator(provider);
|
return new DefaultObjectValidator(provider, new ValidatorCache());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AssertKeysEqual(ModelStateDictionary modelState, params string[] keys)
|
private static void AssertKeysEqual(ModelStateDictionary modelState, params string[] keys)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Microsoft.AspNetCore.Mvc.DataAnnotations.Internal;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
|
{
|
||||||
|
public class ValidatorCacheTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void GetValidators_CachesAllValidators()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var cache = new ValidatorCache();
|
||||||
|
var metadata = new TestModelMetadataProvider().GetMetadataForProperty(typeof(TypeWithProperty), "Property1");
|
||||||
|
var validatorProvider = TestModelValidatorProvider.CreateDefaultProvider();
|
||||||
|
|
||||||
|
// Act - 1
|
||||||
|
var validators1 = cache.GetValidators(metadata, validatorProvider);
|
||||||
|
|
||||||
|
// Assert - 1
|
||||||
|
Assert.Collection(
|
||||||
|
validators1,
|
||||||
|
v => Assert.Same(metadata.ValidatorMetadata[0], Assert.IsType<DataAnnotationsModelValidator>(v).Attribute), // Copied by provider
|
||||||
|
v => Assert.Same(metadata.ValidatorMetadata[1], Assert.IsType<DataAnnotationsModelValidator>(v).Attribute)); // Copied by provider
|
||||||
|
|
||||||
|
// Act - 2
|
||||||
|
var validators2 = cache.GetValidators(metadata, validatorProvider);
|
||||||
|
|
||||||
|
// Assert - 2
|
||||||
|
Assert.Same(validators1, validators2);
|
||||||
|
|
||||||
|
Assert.Collection(
|
||||||
|
validators2,
|
||||||
|
v => Assert.Same(validators1[0], v), // Cached
|
||||||
|
v => Assert.Same(validators1[1], v)); // Cached
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetValidators_DoesNotCacheValidatorsWithIsReusableFalse()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var cache = new ValidatorCache();
|
||||||
|
var metadata = new TestModelMetadataProvider().GetMetadataForProperty(typeof(TypeWithProperty), "Property1");
|
||||||
|
var validatorProvider = new ProviderWithNonReusableValidators();
|
||||||
|
|
||||||
|
// Act - 1
|
||||||
|
var validators1 = cache.GetValidators(metadata, validatorProvider);
|
||||||
|
|
||||||
|
// Assert - 1
|
||||||
|
Assert.Collection(
|
||||||
|
validators1,
|
||||||
|
v => Assert.Same(metadata.ValidatorMetadata[0], Assert.IsType<DataAnnotationsModelValidator>(v).Attribute), // Copied by provider
|
||||||
|
v => Assert.Same(metadata.ValidatorMetadata[1], Assert.IsType<DataAnnotationsModelValidator>(v).Attribute)); // Copied by provider
|
||||||
|
|
||||||
|
// Act - 2
|
||||||
|
var validators2 = cache.GetValidators(metadata, validatorProvider);
|
||||||
|
|
||||||
|
// Assert - 2
|
||||||
|
Assert.NotSame(validators1, validators2);
|
||||||
|
|
||||||
|
Assert.Collection(
|
||||||
|
validators2,
|
||||||
|
v => Assert.Same(validators1[0], v), // Cached
|
||||||
|
v => Assert.NotSame(validators1[1], v)); // Not cached
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TypeWithProperty
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
[StringLength(10)]
|
||||||
|
public string Property1 { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ProviderWithNonReusableValidators : IModelValidatorProvider
|
||||||
|
{
|
||||||
|
public void GetValidators(ModelValidatorProviderContext context)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < context.Results.Count; i++)
|
||||||
|
{
|
||||||
|
var validatorItem = context.Results[i];
|
||||||
|
if (validatorItem.Validator != null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var attribute = validatorItem.ValidatorMetadata as ValidationAttribute;
|
||||||
|
if (attribute == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var validator = new DataAnnotationsModelValidator(
|
||||||
|
new ValidationAttributeAdapterProvider(),
|
||||||
|
attribute,
|
||||||
|
stringLocalizer: null);
|
||||||
|
|
||||||
|
validatorItem.Validator = validator;
|
||||||
|
|
||||||
|
if (attribute is RequiredAttribute)
|
||||||
|
{
|
||||||
|
validatorItem.IsReusable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -100,7 +100,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
GetCompositeBinder(binders),
|
GetCompositeBinder(binders),
|
||||||
valueProvider,
|
valueProvider,
|
||||||
new List<IInputFormatter>(),
|
new List<IInputFormatter>(),
|
||||||
new DefaultObjectValidator(modelMetadataProvider),
|
new DefaultObjectValidator(modelMetadataProvider, new ValidatorCache()),
|
||||||
validator);
|
validator);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -142,7 +142,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
GetCompositeBinder(binders),
|
GetCompositeBinder(binders),
|
||||||
valueProvider,
|
valueProvider,
|
||||||
new List<IInputFormatter>(),
|
new List<IInputFormatter>(),
|
||||||
new DefaultObjectValidator(metadataProvider),
|
new DefaultObjectValidator(metadataProvider, new ValidatorCache()),
|
||||||
validator);
|
validator);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -229,7 +229,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
GetCompositeBinder(binders),
|
GetCompositeBinder(binders),
|
||||||
valueProvider,
|
valueProvider,
|
||||||
new List<IInputFormatter>(),
|
new List<IInputFormatter>(),
|
||||||
new DefaultObjectValidator(metadataProvider),
|
new DefaultObjectValidator(metadataProvider, new ValidatorCache()),
|
||||||
validator,
|
validator,
|
||||||
includePredicate);
|
includePredicate);
|
||||||
|
|
||||||
|
|
@ -314,7 +314,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
GetCompositeBinder(binders),
|
GetCompositeBinder(binders),
|
||||||
valueProvider,
|
valueProvider,
|
||||||
new List<IInputFormatter>(),
|
new List<IInputFormatter>(),
|
||||||
new DefaultObjectValidator(metadataProvider),
|
new DefaultObjectValidator(metadataProvider, new ValidatorCache()),
|
||||||
validator,
|
validator,
|
||||||
m => m.IncludedProperty,
|
m => m.IncludedProperty,
|
||||||
m => m.MyProperty);
|
m => m.MyProperty);
|
||||||
|
|
@ -367,7 +367,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
GetCompositeBinder(binders),
|
GetCompositeBinder(binders),
|
||||||
valueProvider,
|
valueProvider,
|
||||||
new List<IInputFormatter>(),
|
new List<IInputFormatter>(),
|
||||||
new DefaultObjectValidator(metadataProvider),
|
new DefaultObjectValidator(metadataProvider, new ValidatorCache()),
|
||||||
validator);
|
validator);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -579,7 +579,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
GetCompositeBinder(binders),
|
GetCompositeBinder(binders),
|
||||||
valueProvider,
|
valueProvider,
|
||||||
new List<IInputFormatter>(),
|
new List<IInputFormatter>(),
|
||||||
new DefaultObjectValidator(metadataProvider),
|
new DefaultObjectValidator(metadataProvider, new ValidatorCache()),
|
||||||
validator,
|
validator,
|
||||||
includePredicate);
|
includePredicate);
|
||||||
|
|
||||||
|
|
@ -655,7 +655,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
GetCompositeBinder(binders),
|
GetCompositeBinder(binders),
|
||||||
valueProvider,
|
valueProvider,
|
||||||
new List<IInputFormatter>(),
|
new List<IInputFormatter>(),
|
||||||
new DefaultObjectValidator(metadataProvider),
|
new DefaultObjectValidator(metadataProvider, new ValidatorCache()),
|
||||||
validator);
|
validator);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -687,7 +687,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
GetCompositeBinder(binder.Object),
|
GetCompositeBinder(binder.Object),
|
||||||
Mock.Of<IValueProvider>(),
|
Mock.Of<IValueProvider>(),
|
||||||
new List<IInputFormatter>(),
|
new List<IInputFormatter>(),
|
||||||
new DefaultObjectValidator(metadataProvider),
|
new DefaultObjectValidator(metadataProvider, new ValidatorCache()),
|
||||||
Mock.Of<IModelValidatorProvider>(),
|
Mock.Of<IModelValidatorProvider>(),
|
||||||
includePredicate));
|
includePredicate));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +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.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -13,36 +14,37 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
|
||||||
public void GetModelValidators_ReturnsValidatorsFromAllProviders()
|
public void GetModelValidators_ReturnsValidatorsFromAllProviders()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var validator1 = Mock.Of<IModelValidator>();
|
var validatorMetadata = new object();
|
||||||
var validator2 = Mock.Of<IModelValidator>();
|
var validator1 = new ValidatorItem(validatorMetadata);
|
||||||
var validator3 = Mock.Of<IModelValidator>();
|
var validator2 = new ValidatorItem(validatorMetadata);
|
||||||
|
var validator3 = new ValidatorItem(validatorMetadata);
|
||||||
|
|
||||||
var provider1 = new Mock<IModelValidatorProvider>();
|
var provider1 = new Mock<IModelValidatorProvider>();
|
||||||
provider1.Setup(p => p.GetValidators(It.IsAny<ModelValidatorProviderContext>()))
|
provider1.Setup(p => p.GetValidators(It.IsAny<ModelValidatorProviderContext>()))
|
||||||
.Callback<ModelValidatorProviderContext>(c =>
|
.Callback<ModelValidatorProviderContext>(c =>
|
||||||
{
|
{
|
||||||
c.Validators.Add(validator1);
|
c.Results.Add(validator1);
|
||||||
c.Validators.Add(validator2);
|
c.Results.Add(validator2);
|
||||||
});
|
});
|
||||||
|
|
||||||
var provider2 = new Mock<IModelValidatorProvider>();
|
var provider2 = new Mock<IModelValidatorProvider>();
|
||||||
provider2.Setup(p => p.GetValidators(It.IsAny<ModelValidatorProviderContext>()))
|
provider2.Setup(p => p.GetValidators(It.IsAny<ModelValidatorProviderContext>()))
|
||||||
.Callback<ModelValidatorProviderContext>(c =>
|
.Callback<ModelValidatorProviderContext>(c =>
|
||||||
{
|
{
|
||||||
c.Validators.Add(validator3);
|
c.Results.Add(validator3);
|
||||||
});
|
});
|
||||||
|
|
||||||
var compositeModelValidator = new CompositeModelValidatorProvider(new[] { provider1.Object, provider2.Object });
|
var compositeModelValidator = new CompositeModelValidatorProvider(new[] { provider1.Object, provider2.Object });
|
||||||
var modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(string));
|
var modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(string));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var validatorProviderContext = new ModelValidatorProviderContext(modelMetadata);
|
var validatorProviderContext = new ModelValidatorProviderContext(modelMetadata, new List<ValidatorItem>());
|
||||||
compositeModelValidator.GetValidators(validatorProviderContext);
|
compositeModelValidator.GetValidators(validatorProviderContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(
|
Assert.Equal(
|
||||||
new[] { validator1, validator2, validator3 },
|
new[] { validator1, validator2, validator3 },
|
||||||
validatorProviderContext.Validators.ToArray());
|
validatorProviderContext.Results.ToArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +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.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
|
|
@ -25,14 +26,14 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
||||||
var mockValidatable = Mock.Of<IValidatableObject>();
|
var mockValidatable = Mock.Of<IValidatableObject>();
|
||||||
var metadata = _metadataProvider.GetMetadataForType(mockValidatable.GetType());
|
var metadata = _metadataProvider.GetMetadataForType(mockValidatable.GetType());
|
||||||
|
|
||||||
var providerContext = new ModelValidatorProviderContext(metadata);
|
var providerContext = new ModelValidatorProviderContext(metadata, GetValidatorItems(metadata));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetValidators(providerContext);
|
provider.GetValidators(providerContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var validator = Assert.Single(providerContext.Validators);
|
var validatorItem = Assert.Single(providerContext.Results);
|
||||||
Assert.IsType<ValidatableObjectAdapter>(validator);
|
Assert.IsType<ValidatableObjectAdapter>(validatorItem.Validator);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -46,15 +47,15 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
||||||
typeof(ClassWithProperty),
|
typeof(ClassWithProperty),
|
||||||
"PropertyWithMultipleValidationAttributes");
|
"PropertyWithMultipleValidationAttributes");
|
||||||
|
|
||||||
var providerContext = new ModelValidatorProviderContext(metadata);
|
var providerContext = new ModelValidatorProviderContext(metadata, GetValidatorItems(metadata));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetValidators(providerContext);
|
provider.GetValidators(providerContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(4, providerContext.Validators.Count);
|
Assert.Equal(4, providerContext.Results.Count);
|
||||||
Assert.IsAssignableFrom<RequiredAttribute>(((DataAnnotationsModelValidator)providerContext.Validators[0]).Attribute);
|
Assert.IsAssignableFrom<RequiredAttribute>(((DataAnnotationsModelValidator)providerContext.Results[0].Validator).Attribute);
|
||||||
Assert.IsAssignableFrom<RequiredAttribute>(((DataAnnotationsModelValidator)providerContext.Validators[1]).Attribute);
|
Assert.IsAssignableFrom<RequiredAttribute>(((DataAnnotationsModelValidator)providerContext.Results[1].Validator).Attribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -67,14 +68,14 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
||||||
stringLocalizerFactory: null);
|
stringLocalizerFactory: null);
|
||||||
var metadata = _metadataProvider.GetMetadataForType(typeof(DummyClassWithDummyValidationAttribute));
|
var metadata = _metadataProvider.GetMetadataForType(typeof(DummyClassWithDummyValidationAttribute));
|
||||||
|
|
||||||
var providerContext = new ModelValidatorProviderContext(metadata);
|
var providerContext = new ModelValidatorProviderContext(metadata, GetValidatorItems(metadata));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetValidators(providerContext);
|
provider.GetValidators(providerContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var validator = providerContext.Validators.Single();
|
var validatorItem = providerContext.Results.Single();
|
||||||
Assert.IsType<DataAnnotationsModelValidator>(validator);
|
Assert.IsType<DataAnnotationsModelValidator>(validatorItem.Validator);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DummyValidationAttribute : ValidationAttribute
|
private class DummyValidationAttribute : ValidationAttribute
|
||||||
|
|
@ -99,13 +100,24 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
||||||
var mockValidatable = new Mock<IValidatableObject>();
|
var mockValidatable = new Mock<IValidatableObject>();
|
||||||
var metadata = _metadataProvider.GetMetadataForType(mockValidatable.Object.GetType());
|
var metadata = _metadataProvider.GetMetadataForType(mockValidatable.Object.GetType());
|
||||||
|
|
||||||
var providerContext = new ModelValidatorProviderContext(metadata);
|
var providerContext = new ModelValidatorProviderContext(metadata, GetValidatorItems(metadata));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetValidators(providerContext);
|
provider.GetValidators(providerContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Single(providerContext.Validators);
|
Assert.Single(providerContext.Results);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IList<ValidatorItem> GetValidatorItems(ModelMetadata metadata)
|
||||||
|
{
|
||||||
|
var items = new List<ValidatorItem>(metadata.ValidatorMetadata.Count);
|
||||||
|
for (var i = 0; i < metadata.ValidatorMetadata.Count; i++)
|
||||||
|
{
|
||||||
|
items.Add(new ValidatorItem(metadata.ValidatorMetadata[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ObservableModel
|
private class ObservableModel
|
||||||
|
|
|
||||||
|
|
@ -22,16 +22,16 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
||||||
var validatorProvider = TestModelValidatorProvider.CreateDefaultProvider();
|
var validatorProvider = TestModelValidatorProvider.CreateDefaultProvider();
|
||||||
|
|
||||||
var metadata = metadataProvider.GetMetadataForType(typeof(ValidatableObject));
|
var metadata = metadataProvider.GetMetadataForType(typeof(ValidatableObject));
|
||||||
var context = new ModelValidatorProviderContext(metadata);
|
var context = new ModelValidatorProviderContext(metadata, GetValidatorItems(metadata));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
validatorProvider.GetValidators(context);
|
validatorProvider.GetValidators(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var validators = context.Validators;
|
var validatorItems = context.Results;
|
||||||
|
|
||||||
var validator = Assert.Single(validators);
|
var validatorItem = Assert.Single(validatorItems);
|
||||||
Assert.IsType<ValidatableObjectAdapter>(validator);
|
Assert.IsType<ValidatableObjectAdapter>(validatorItem.Validator);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -42,16 +42,16 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
||||||
var validatorProvider = TestModelValidatorProvider.CreateDefaultProvider();
|
var validatorProvider = TestModelValidatorProvider.CreateDefaultProvider();
|
||||||
|
|
||||||
var metadata = metadataProvider.GetMetadataForType(typeof(ModelValidatorAttributeOnClass));
|
var metadata = metadataProvider.GetMetadataForType(typeof(ModelValidatorAttributeOnClass));
|
||||||
var context = new ModelValidatorProviderContext(metadata);
|
var context = new ModelValidatorProviderContext(metadata, GetValidatorItems(metadata));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
validatorProvider.GetValidators(context);
|
validatorProvider.GetValidators(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var validators = context.Validators;
|
var validatorItems = context.Results;
|
||||||
|
|
||||||
var validator = Assert.Single(validators);
|
var validatorItem = Assert.Single(validatorItems);
|
||||||
var customModelValidator = Assert.IsType<CustomModelValidatorAttribute>(validator);
|
var customModelValidator = Assert.IsType<CustomModelValidatorAttribute>(validatorItem.Validator);
|
||||||
Assert.Equal("Class", customModelValidator.Tag);
|
Assert.Equal("Class", customModelValidator.Tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,16 +65,16 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
||||||
var metadata = metadataProvider.GetMetadataForProperty(
|
var metadata = metadataProvider.GetMetadataForProperty(
|
||||||
typeof(ModelValidatorAttributeOnProperty),
|
typeof(ModelValidatorAttributeOnProperty),
|
||||||
nameof(ModelValidatorAttributeOnProperty.Property));
|
nameof(ModelValidatorAttributeOnProperty.Property));
|
||||||
var context = new ModelValidatorProviderContext(metadata);
|
var context = new ModelValidatorProviderContext(metadata, GetValidatorItems(metadata));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
validatorProvider.GetValidators(context);
|
validatorProvider.GetValidators(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var validators = context.Validators;
|
var validatorItems = context.Results;
|
||||||
|
|
||||||
var validator = Assert.IsType<CustomModelValidatorAttribute>(Assert.Single(validators));
|
var validatorItem = Assert.IsType<CustomModelValidatorAttribute>(Assert.Single(validatorItems).Validator);
|
||||||
Assert.Equal("Property", validator.Tag);
|
Assert.Equal("Property", validatorItem.Tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -87,17 +87,17 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
||||||
var metadata = metadataProvider.GetMetadataForProperty(
|
var metadata = metadataProvider.GetMetadataForProperty(
|
||||||
typeof(ModelValidatorAttributeOnPropertyAndClass),
|
typeof(ModelValidatorAttributeOnPropertyAndClass),
|
||||||
nameof(ModelValidatorAttributeOnPropertyAndClass.Property));
|
nameof(ModelValidatorAttributeOnPropertyAndClass.Property));
|
||||||
var context = new ModelValidatorProviderContext(metadata);
|
var context = new ModelValidatorProviderContext(metadata, GetValidatorItems(metadata));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
validatorProvider.GetValidators(context);
|
validatorProvider.GetValidators(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var validators = context.Validators;
|
var validatorItems = context.Results;
|
||||||
|
|
||||||
Assert.Equal(2, validators.Count);
|
Assert.Equal(2, validatorItems.Count);
|
||||||
Assert.Single(validators, v => Assert.IsType<CustomModelValidatorAttribute>(v).Tag == "Class");
|
Assert.Single(validatorItems, v => Assert.IsType<CustomModelValidatorAttribute>(v.Validator).Tag == "Class");
|
||||||
Assert.Single(validators, v => Assert.IsType<CustomModelValidatorAttribute>(v).Tag == "Property");
|
Assert.Single(validatorItems, v => Assert.IsType<CustomModelValidatorAttribute>(v.Validator).Tag == "Property");
|
||||||
}
|
}
|
||||||
|
|
||||||
// RangeAttribute is an example of a ValidationAttribute with it's own adapter type.
|
// RangeAttribute is an example of a ValidationAttribute with it's own adapter type.
|
||||||
|
|
@ -191,6 +191,17 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
||||||
Assert.Single(validators, v => v is StringLengthAttributeAdapter);
|
Assert.Single(validators, v => v is StringLengthAttributeAdapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IList<ValidatorItem> GetValidatorItems(ModelMetadata metadata)
|
||||||
|
{
|
||||||
|
var items = new List<ValidatorItem>(metadata.ValidatorMetadata.Count);
|
||||||
|
for (var i = 0; i < metadata.ValidatorMetadata.Count; i++)
|
||||||
|
{
|
||||||
|
items.Add(new ValidatorItem(metadata.ValidatorMetadata[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
private class ValidatableObject : IValidatableObject
|
private class ValidatableObject : IValidatableObject
|
||||||
{
|
{
|
||||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
||||||
|
|
||||||
public static IObjectModelValidator GetObjectValidator(IModelMetadataProvider metadataProvider)
|
public static IObjectModelValidator GetObjectValidator(IModelMetadataProvider metadataProvider)
|
||||||
{
|
{
|
||||||
return new DefaultObjectValidator(metadataProvider);
|
return new DefaultObjectValidator(metadataProvider, new ValidatorCache());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HttpContext GetHttpContext(
|
private static HttpContext GetHttpContext(
|
||||||
|
|
|
||||||
|
|
@ -302,7 +302,7 @@ namespace Microsoft.AspNetCore.Mvc.Test
|
||||||
{
|
{
|
||||||
ControllerContext = controllerContext,
|
ControllerContext = controllerContext,
|
||||||
MetadataProvider = metadataProvider,
|
MetadataProvider = metadataProvider,
|
||||||
ObjectValidator = new DefaultObjectValidator(metadataProvider),
|
ObjectValidator = new DefaultObjectValidator(metadataProvider, new ValidatorCache()),
|
||||||
TempData = tempData,
|
TempData = tempData,
|
||||||
ViewData = viewData,
|
ViewData = viewData,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue