3 // Marek Habersack <grendel@twistedcode.net>
5 // Copyright (C) 2011 Novell Inc. http://novell.com
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System.Collections.Generic;
30 using System.ComponentModel;
32 using System.Reflection;
34 namespace System.ComponentModel.DataAnnotations
36 // TODO: we could probably use some kind of type cache here
37 public static class Validator
39 public static bool TryValidateObject (object instance, ValidationContext validationContext, ICollection <ValidationResult> validationResults)
41 return TryValidateObject (instance, validationContext, validationResults, false);
44 public static bool TryValidateObject (object instance, ValidationContext validationContext, ICollection <ValidationResult> validationResults, bool validateAllProperties)
47 throw new ArgumentNullException ("instance");
49 if (validationContext == null)
50 throw new ArgumentNullException ("validationContext");
52 if (!Object.ReferenceEquals (instance, validationContext.ObjectInstance))
53 throw new ArgumentException ("The instance provided must match the ObjectInstance on the ValidationContext supplied.", "instance");
56 Type instanceType = instance.GetType ();
57 TypeDescriptor.GetAttributes (instanceType).Validate <ValidationAttribute> (instance, validationContext, validationResults, ref valid);
59 PropertyDescriptorCollection properties = TypeDescriptor.GetProperties (instance);
60 if (properties != PropertyDescriptorCollection.Empty && properties.Count > 0) {
61 foreach (PropertyDescriptor pdesc in properties) {
62 object value = pdesc.GetValue (instance);
63 ValidateProperty (pdesc, value, validationContext, validationResults, validateAllProperties, ref valid);
70 static void ValidateProperty (PropertyDescriptor pdesc, object value, ValidationContext validationContext, ICollection <ValidationResult> validationResults,
71 bool validateAll, ref bool valid)
73 AttributeCollection attributes = pdesc.Attributes;
74 attributes.Validate <RequiredAttribute> (value, validationContext, validationResults, ref valid);
76 attributes.ValidateExcept <RequiredAttribute> (value, validationContext, validationResults, ref valid);
79 static PropertyDescriptor GetProperty (Type type, string propertyName, object value)
81 if (String.IsNullOrEmpty (propertyName))
82 throw new ArgumentNullException ("propertyName");
84 PropertyDescriptorCollection properties = TypeDescriptor.GetProperties (type);
85 PropertyDescriptor pdesc = null;
86 if (properties != PropertyDescriptorCollection.Empty && properties.Count > 0)
87 pdesc = properties.Find (propertyName, false);
90 throw new ArgumentException (String.Format ("The type '{0}' does not contain a public property named '{1}'.", type.Name, propertyName), "propertyName");
92 Type valueType = value == null ? null : value.GetType ();
93 Type propertyType = pdesc.PropertyType;
94 bool invalidType = false;
96 if (valueType == null)
97 invalidType = (propertyType.IsValueType && Nullable.GetUnderlyingType(propertyType) == null);
99 invalidType = !propertyType.IsAssignableFrom(valueType);
102 throw new ArgumentException (String.Format ("The value of property '{0}' must be of type '{1}'.", propertyName, propertyType.FullName), "propertyName");
107 public static bool TryValidateProperty (object value, ValidationContext validationContext, ICollection <ValidationResult> validationResults)
109 // LAMESPEC: value can be null, validationContext must not
110 if (validationContext == null)
111 throw new ArgumentNullException ("validationContext");
113 PropertyDescriptor pdesc = GetProperty (validationContext.ObjectType, validationContext.MemberName, value);
116 ValidateProperty (pdesc, value, validationContext, validationResults, true, ref valid);
121 public static bool TryValidateValue (object value, ValidationContext validationContext, ICollection<ValidationResult> validationResults,
122 IEnumerable <ValidationAttribute> validationAttributes)
124 if (validationContext == null)
125 throw new ArgumentNullException ("validationContext");
127 ValidationResult result;
129 // It appears .NET makes this call before checking whether
130 // validationAttributes is null...
131 ValidationAttribute vattr = validationAttributes.FirstOrDefault <ValidationAttribute> (attr => attr is RequiredAttribute);
133 result = vattr.GetValidationResult (value, validationContext);
134 if (result != ValidationResult.Success) {
135 if (validationResults != null)
136 validationResults.Add (result);
141 if (validationAttributes == null)
145 foreach (ValidationAttribute attr in validationAttributes) {
146 if (attr == null || (attr is RequiredAttribute))
149 result = attr.GetValidationResult (value, validationContext);
150 if (result != ValidationResult.Success) {
152 if (validationResults != null)
153 validationResults.Add (result);
160 public static void ValidateObject (object instance, ValidationContext validationContext)
162 ValidateObject (instance, validationContext, false);
165 public static void ValidateObject (object instance, ValidationContext validationContext, bool validateAllProperties)
167 if (instance == null)
168 throw new ArgumentNullException ("instance");
169 if (validationContext == null)
170 throw new ArgumentNullException ("validationContext");
172 var validationResults = new List <ValidationResult> ();
173 if (TryValidateObject (instance, validationContext, validationResults, validateAllProperties))
176 ValidationResult result = validationResults.Count > 0 ? validationResults [0] : null;
177 throw new ValidationException (result, null, instance);
180 public static void ValidateProperty (object value, ValidationContext validationContext)
182 if (validationContext == null)
183 throw new ArgumentNullException ("validationContext");
185 var validationResults = new List <ValidationResult> ();
186 if (TryValidateProperty (value, validationContext, validationResults))
189 ValidationResult result = validationResults.Count > 0 ? validationResults [0] : null;
190 throw new ValidationException (result, null, value);
193 public static void ValidateValue (object value, ValidationContext validationContext, IEnumerable <ValidationAttribute> validationAttributes)
195 if (validationContext == null)
196 throw new ArgumentNullException ("validationContext");
198 var validationResults = new List <ValidationResult> ();
199 if (TryValidateValue (value, validationContext, validationResults, validationAttributes))
202 ValidationResult result = validationResults.Count > 0 ? validationResults [0] : null;
203 throw new ValidationException (result, null, value);