// 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;
using System.ComponentModel.DataAnnotations;
#if NETSTANDARD1_3
using System.Reflection;
#endif
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
{
///
/// An implementation of which provides validators
/// for attributes which derive from . It also provides
/// a validator for types which implement .
///
public class DataAnnotationsModelValidatorProvider : IModelValidatorProvider
{
private readonly IOptions _options;
private readonly IStringLocalizerFactory _stringLocalizerFactory;
private readonly IValidationAttributeAdapterProvider _validationAttributeAdapterProvider;
///
/// Create a new instance of .
///
/// The
/// that supplies s.
/// The .
/// The .
/// and
/// are nullable only for testing ease.
public DataAnnotationsModelValidatorProvider(
IValidationAttributeAdapterProvider validationAttributeAdapterProvider,
IOptions options,
IStringLocalizerFactory stringLocalizerFactory)
{
if (validationAttributeAdapterProvider == null)
{
throw new ArgumentNullException(nameof(validationAttributeAdapterProvider));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
_validationAttributeAdapterProvider = validationAttributeAdapterProvider;
_options = options;
_stringLocalizerFactory = stringLocalizerFactory;
}
public void CreateValidators(ModelValidatorProviderContext context)
{
IStringLocalizer stringLocalizer = null;
if (_stringLocalizerFactory != null && _options.Value.DataAnnotationLocalizerProvider != null)
{
stringLocalizer = _options.Value.DataAnnotationLocalizerProvider(
context.ModelMetadata.ContainerType ?? context.ModelMetadata.ModelType,
_stringLocalizerFactory);
}
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(
_validationAttributeAdapterProvider,
attribute,
stringLocalizer);
validatorItem.Validator = validator;
validatorItem.IsReusable = true;
// 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.Results.Remove(validatorItem);
context.Results.Insert(0, validatorItem);
}
}
// Produce a validator if the type supports IValidatableObject
if (typeof(IValidatableObject).IsAssignableFrom(context.ModelMetadata.ModelType))
{
context.Results.Add(new ValidatorItem
{
Validator = new ValidatableObjectAdapter(),
IsReusable = true
});
}
}
}
}