// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; namespace Microsoft.AspNet.Mvc.ModelBinding { /// /// An implementation of which providers validators /// for attributes which derive from . It also provides /// a validator for types which implement . To support /// client side validation, you can either register adapters through the static methods /// on this class, or by having your validation attributes implement /// . The logic to support IClientValidatable /// is implemented in . /// public class DataAnnotationsModelValidatorProvider : AssociatedValidatorProvider { // A factory for validators based on ValidationAttribute. internal delegate IModelValidator DataAnnotationsModelValidationFactory(ValidationAttribute attribute); // A factory for validators based on IValidatableObject private delegate IModelValidator DataAnnotationsValidatableObjectAdapterFactory(); private static bool _addImplicitRequiredAttributeForValueTypes = true; private readonly Dictionary _attributeFactories = BuildAttributeFactoriesDictionary(); // Factories for validation attributes private static readonly DataAnnotationsModelValidationFactory _defaultAttributeFactory = (attribute) => new DataAnnotationsModelValidator(attribute); // Factories for IValidatableObject models private static readonly DataAnnotationsValidatableObjectAdapterFactory _defaultValidatableFactory = () => new ValidatableObjectAdapter(); internal Dictionary AttributeFactories { get { return _attributeFactories; } } private static bool AddImplicitRequiredAttributeForValueTypes { get { return _addImplicitRequiredAttributeForValueTypes; } set { _addImplicitRequiredAttributeForValueTypes = value; } } protected override IEnumerable GetValidators(ModelMetadata metadata, IEnumerable attributes) { var results = new List(); // Produce a validator for each validation attribute we find foreach (var attribute in attributes.OfType()) { DataAnnotationsModelValidationFactory factory; if (!_attributeFactories.TryGetValue(attribute.GetType(), out factory)) { factory = _defaultAttributeFactory; } results.Add(factory(attribute)); } // Produce a validator if the type supports IValidatableObject if (typeof(IValidatableObject).IsAssignableFrom(metadata.ModelType)) { results.Add(_defaultValidatableFactory()); } return results; } private static Dictionary BuildAttributeFactoriesDictionary() { var dict = new Dictionary(); AddValidationAttributeAdapter(dict, typeof(RegularExpressionAttribute), (attribute) => new RegularExpressionAttributeAdapter((RegularExpressionAttribute)attribute)); AddValidationAttributeAdapter(dict, typeof(MaxLengthAttribute), (attribute) => new MaxLengthAttributeAdapter((MaxLengthAttribute)attribute)); AddValidationAttributeAdapter(dict, typeof(MinLengthAttribute), (attribute) => new MinLengthAttributeAdapter((MinLengthAttribute)attribute)); AddValidationAttributeAdapter(dict, typeof(CompareAttribute), (attribute) => new CompareAttributeAdapter((CompareAttribute)attribute)); AddDataTypeAttributeAdapter(dict, typeof(UrlAttribute), "url"); return dict; } private static void AddValidationAttributeAdapter(Dictionary dictionary, Type validationAttributeType, DataAnnotationsModelValidationFactory factory) { if (validationAttributeType != null) { dictionary.Add(validationAttributeType, factory); } } private static void AddDataTypeAttributeAdapter(Dictionary dictionary, Type attributeType, string ruleName) { AddValidationAttributeAdapter( dictionary, attributeType, (attribute) => new DataTypeAttributeAdapter((DataTypeAttribute)attribute, ruleName)); } } }