1 /* ****************************************************************************
\r
3 * Copyright (c) Microsoft Corporation. All rights reserved.
\r
5 * This software is subject to the Microsoft Public License (Ms-PL).
\r
6 * A copy of the license can be found in the license.htm file included
\r
7 * in this distribution.
\r
9 * You must not remove this notice, or any other, from this software.
\r
11 * ***************************************************************************/
\r
13 namespace System.Web.Mvc {
\r
15 using System.Collections.Generic;
\r
16 using System.ComponentModel.DataAnnotations;
\r
17 using System.Globalization;
\r
19 using System.Reflection;
\r
20 using System.Threading;
\r
21 using System.Web.Mvc.Resources;
\r
23 public delegate ModelValidator DataAnnotationsModelValidationFactory(ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute);
\r
25 public class DataAnnotationsModelValidatorProvider : AssociatedValidatorProvider {
\r
26 private static bool _addImplicitRequiredAttributeForValueTypes = true;
\r
27 private static ReaderWriterLockSlim _adaptersLock = new ReaderWriterLockSlim();
\r
29 internal static DataAnnotationsModelValidationFactory DefaultAttributeFactory = DataAnnotationsModelValidator.Create;
\r
30 internal static Dictionary<Type, DataAnnotationsModelValidationFactory> AttributeFactories = new Dictionary<Type, DataAnnotationsModelValidationFactory>() {
\r
32 typeof(RangeAttribute),
\r
33 (metadata, context, attribute) => new RangeAttributeAdapter(metadata, context, (RangeAttribute)attribute)
\r
36 typeof(RegularExpressionAttribute),
\r
37 (metadata, context, attribute) => new RegularExpressionAttributeAdapter(metadata, context, (RegularExpressionAttribute)attribute)
\r
40 typeof(RequiredAttribute),
\r
41 (metadata, context, attribute) => new RequiredAttributeAdapter(metadata, context, (RequiredAttribute)attribute)
\r
44 typeof(StringLengthAttribute),
\r
45 (metadata, context, attribute) => new StringLengthAttributeAdapter(metadata, context, (StringLengthAttribute)attribute)
\r
49 public static bool AddImplicitRequiredAttributeForValueTypes {
\r
51 return _addImplicitRequiredAttributeForValueTypes;
\r
54 _addImplicitRequiredAttributeForValueTypes = value;
\r
58 protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes) {
\r
59 _adaptersLock.EnterReadLock();
\r
62 List<ModelValidator> results = new List<ModelValidator>();
\r
64 if (AddImplicitRequiredAttributeForValueTypes &&
\r
65 metadata.IsRequired &&
\r
66 !attributes.Any(a => a is RequiredAttribute)) {
\r
67 attributes = attributes.Concat(new[] { new RequiredAttribute() });
\r
70 foreach (ValidationAttribute attribute in attributes.OfType<ValidationAttribute>()) {
\r
71 DataAnnotationsModelValidationFactory factory;
\r
72 if (!AttributeFactories.TryGetValue(attribute.GetType(), out factory)) {
\r
73 factory = DefaultAttributeFactory;
\r
75 results.Add(factory(metadata, context, attribute));
\r
81 _adaptersLock.ExitReadLock();
\r
85 public static void RegisterAdapter(Type attributeType, Type adapterType) {
\r
86 ValidateAttributeType(attributeType);
\r
87 ValidateAdapterType(adapterType);
\r
88 ConstructorInfo constructor = GetAdapterConstructor(attributeType, adapterType);
\r
90 _adaptersLock.EnterWriteLock();
\r
93 AttributeFactories[attributeType] = (metadata, context, attribute) => (ModelValidator)constructor.Invoke(new object[] { metadata, context, attribute });
\r
96 _adaptersLock.ExitWriteLock();
\r
100 public static void RegisterAdapterFactory(Type attributeType, DataAnnotationsModelValidationFactory factory) {
\r
101 ValidateAttributeType(attributeType);
\r
102 ValidateFactory(factory);
\r
104 _adaptersLock.EnterWriteLock();
\r
107 AttributeFactories[attributeType] = factory;
\r
110 _adaptersLock.ExitWriteLock();
\r
114 public static void RegisterDefaultAdapter(Type adapterType) {
\r
115 ValidateAdapterType(adapterType);
\r
116 ConstructorInfo constructor = GetAdapterConstructor(typeof(ValidationAttribute), adapterType);
\r
118 DefaultAttributeFactory = (metadata, context, attribute) => (ModelValidator)constructor.Invoke(new object[] { metadata, context, attribute });
\r
121 public static void RegisterDefaultAdapterFactory(DataAnnotationsModelValidationFactory factory) {
\r
122 ValidateFactory(factory);
\r
124 DefaultAttributeFactory = factory;
\r
129 private static ConstructorInfo GetAdapterConstructor(Type attributeType, Type adapterType) {
\r
130 ConstructorInfo constructor = adapterType.GetConstructor(new[] { typeof(ModelMetadata), typeof(ControllerContext), attributeType });
\r
131 if (constructor == null) {
\r
132 throw new ArgumentException(
\r
134 CultureInfo.CurrentCulture,
\r
135 MvcResources.DataAnnotationsModelValidatorProvider_ConstructorRequirements,
\r
136 adapterType.FullName,
\r
137 typeof(ModelMetadata).FullName,
\r
138 typeof(ControllerContext).FullName,
\r
139 attributeType.FullName
\r
145 return constructor;
\r
148 private static void ValidateAdapterType(Type adapterType) {
\r
149 if (adapterType == null) {
\r
150 throw new ArgumentNullException("adapterType");
\r
152 if (!typeof(ModelValidator).IsAssignableFrom(adapterType)) {
\r
153 throw new ArgumentException(
\r
155 CultureInfo.CurrentCulture,
\r
156 MvcResources.Common_TypeMustDriveFromType,
\r
157 adapterType.FullName,
\r
158 typeof(ModelValidator).FullName
\r
165 private static void ValidateAttributeType(Type attributeType) {
\r
166 if (attributeType == null) {
\r
167 throw new ArgumentNullException("attributeType");
\r
169 if (!typeof(ValidationAttribute).IsAssignableFrom(attributeType)) {
\r
170 throw new ArgumentException(
\r
172 CultureInfo.CurrentCulture,
\r
173 MvcResources.Common_TypeMustDriveFromType,
\r
174 attributeType.FullName,
\r
175 typeof(ValidationAttribute).FullName
\r
181 private static void ValidateFactory(DataAnnotationsModelValidationFactory factory) {
\r
182 if (factory == null) {
\r
183 throw new ArgumentNullException("factory");
\r