1616namespace System . Web . Http . Validation
1717{
1818 /// <summary>
19- /// Recursively validate an object.
19+ /// Recursively validate an object.
2020 /// </summary>
2121 public class DefaultBodyModelValidator : IBodyModelValidator
2222 {
23- private interface IKeyBuilder
24- {
25- string AppendTo ( string prefix ) ;
26- }
27-
2823 /// <summary>
2924 /// Determines whether the <paramref name="model"/> is valid and adds any validation errors to the <paramref name="actionContext"/>'s <see cref="ModelStateDictionary"/>
3025 /// </summary>
@@ -64,14 +59,14 @@ public bool Validate(object model, Type type, ModelMetadataProvider metadataProv
6459 }
6560
6661 ModelMetadata metadata = metadataProvider . GetMetadataForType ( ( ) => model , type ) ;
67- ValidationContext validationContext = new ValidationContext ( )
62+ BodyModelValidatorContext validationContext = new BodyModelValidatorContext
6863 {
6964 MetadataProvider = metadataProvider ,
7065 ActionContext = actionContext ,
7166 ValidatorCache = actionContext . GetValidatorCache ( ) ,
7267 ModelState = actionContext . ModelState ,
7368 Visited = new HashSet < object > ( ReferenceEqualityComparer . Instance ) ,
74- KeyBuilders = new Stack < IKeyBuilder > ( ) ,
69+ KeyBuilders = new Stack < IBodyModelValidatorKeyBuilder > ( ) ,
7570 RootPrefix = keyPrefix
7671 } ;
7772 return ValidateNodeAndChildren ( metadata , validationContext , container : null , validators : null ) ;
@@ -87,12 +82,36 @@ public virtual bool ShouldValidateType(Type type)
8782 return ! MediaTypeFormatterCollection . IsTypeExcludedFromValidation ( type ) ;
8883 }
8984
85+ /// <summary>
86+ /// Recursively validate the given <paramref name="metadata"/> and <paramref name="container"/>.
87+ /// </summary>
88+ /// <param name="metadata">The <see cref="ModelMetadata"/> for the object to validate.</param>
89+ /// <param name="validationContext">The <see cref="BodyModelValidatorContext"/>.</param>
90+ /// <param name="container">The object containing the object to validate.</param>
91+ /// <param name="validators">The collection of <see cref="ModelValidator"/>s.</param>
92+ /// <returns>
93+ /// <see langword="true"/> if validation succeeds for the given <paramref name="metadata"/>,
94+ /// <paramref name="container"/>, and child nodes; <see langword="false"/> otherwise.
95+ /// </returns>
9096 [ SuppressMessage ( "Microsoft.Design" , "CA1031:DoNotCatchGeneralExceptionTypes" , Justification = "See comment below" ) ]
91- private bool ValidateNodeAndChildren ( ModelMetadata metadata , ValidationContext validationContext , object container , IEnumerable < ModelValidator > validators )
97+ protected virtual bool ValidateNodeAndChildren (
98+ ModelMetadata metadata ,
99+ BodyModelValidatorContext validationContext ,
100+ object container ,
101+ IEnumerable < ModelValidator > validators )
92102 {
93103 // Recursion guard to avoid stack overflows
94104 RuntimeHelpers . EnsureSufficientExecutionStack ( ) ;
95105
106+ if ( metadata == null )
107+ {
108+ throw Error . ArgumentNull ( "metadata" ) ;
109+ }
110+ if ( validationContext == null )
111+ {
112+ throw Error . ArgumentNull ( "validationContext" ) ;
113+ }
114+
96115 object model = null ;
97116 try
98117 {
@@ -155,8 +174,26 @@ private bool ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext v
155174 return isValid ;
156175 }
157176
158- private bool ValidateProperties ( ModelMetadata metadata , ValidationContext validationContext )
177+ /// <summary>
178+ /// Recursively validate the properties of the given <paramref name="metadata"/>.
179+ /// </summary>
180+ /// <param name="metadata">The <see cref="ModelMetadata"/> for the object to validate.</param>
181+ /// <param name="validationContext">The <see cref="BodyModelValidatorContext"/>.</param>
182+ /// <returns>
183+ /// <see langword="true"/> if validation succeeds for all properties in <paramref name="metadata"/>;
184+ /// <see langword="false"/> otherwise.
185+ /// </returns>
186+ protected virtual bool ValidateProperties ( ModelMetadata metadata , BodyModelValidatorContext validationContext )
159187 {
188+ if ( metadata == null )
189+ {
190+ throw Error . ArgumentNull ( "metadata" ) ;
191+ }
192+ if ( validationContext == null )
193+ {
194+ throw Error . ArgumentNull ( "validationContext" ) ;
195+ }
196+
160197 bool isValid = true ;
161198 PropertyScope propertyScope = new PropertyScope ( ) ;
162199 validationContext . KeyBuilders . Push ( propertyScope ) ;
@@ -172,8 +209,26 @@ private bool ValidateProperties(ModelMetadata metadata, ValidationContext valida
172209 return isValid ;
173210 }
174211
175- private bool ValidateElements ( IEnumerable model , ValidationContext validationContext )
212+ /// <summary>
213+ /// Recursively validate the elements of the <paramref name="model"/> collection.
214+ /// </summary>
215+ /// <param name="model">The <see cref="IEnumerable"/> instance containing the elements to validate.</param>
216+ /// <param name="validationContext">The <see cref="BodyModelValidatorContext"/>.</param>
217+ /// <returns>
218+ /// <see langword="true"/> if validation succeeds for all elements of <paramref name="model"/>;
219+ /// <see langword="false"/> otherwise.
220+ /// </returns>
221+ protected virtual bool ValidateElements ( IEnumerable model , BodyModelValidatorContext validationContext )
176222 {
223+ if ( model == null )
224+ {
225+ throw Error . ArgumentNull ( "model" ) ;
226+ }
227+ if ( validationContext == null )
228+ {
229+ throw Error . ArgumentNull ( "validationContext" ) ;
230+ }
231+
177232 bool isValid = true ;
178233 Type elementType = GetElementType ( model . GetType ( ) ) ;
179234 ModelMetadata elementMetadata = validationContext . MetadataProvider . GetMetadataForType ( null , elementType ) ;
@@ -207,15 +262,39 @@ private bool ValidateElements(IEnumerable model, ValidationContext validationCon
207262 return isValid ;
208263 }
209264
210- // Validates a single node (not including children)
211- // Returns true if validation passes successfully
212- private static bool ShallowValidate ( ModelMetadata metadata , ValidationContext validationContext , object container , IEnumerable < ModelValidator > validators )
265+ /// <summary>
266+ /// Validate a single node, not including its children.
267+ /// </summary>
268+ /// <param name="metadata">The <see cref="ModelMetadata"/>.</param>
269+ /// <param name="validationContext">The <see cref="BodyModelValidatorContext"/>.</param>
270+ /// <param name="container">The object to validate.</param>
271+ /// <param name="validators">The collection of <see cref="ModelValidator"/>s.</param>
272+ /// <returns>
273+ /// <see langword="true"/> if validation succeeds for the given <paramref name="metadata"/> and
274+ /// <paramref name="container"/>; <see langword="false"/> otherwise.
275+ /// </returns>
276+ protected virtual bool ShallowValidate (
277+ ModelMetadata metadata ,
278+ BodyModelValidatorContext validationContext ,
279+ object container ,
280+ IEnumerable < ModelValidator > validators )
213281 {
282+ if ( metadata == null )
283+ {
284+ throw Error . ArgumentNull ( "metadata" ) ;
285+ }
286+ if ( validationContext == null )
287+ {
288+ throw Error . ArgumentNull ( "validationContext" ) ;
289+ }
290+ if ( validators == null )
291+ {
292+ throw Error . ArgumentNull ( "validators" ) ;
293+ }
294+
214295 bool isValid = true ;
215296 string modelKey = null ;
216297
217- Contract . Assert ( validators != null ) ;
218-
219298 // When the are no validators we bail quickly. This saves a GetEnumerator allocation.
220299 // In a large array (tens of thousands or more) scenario it's very significant.
221300 ICollection validatorsAsCollection = validators as ICollection ;
@@ -231,7 +310,7 @@ private static bool ShallowValidate(ModelMetadata metadata, ValidationContext va
231310 if ( modelKey == null )
232311 {
233312 modelKey = validationContext . RootPrefix ;
234- foreach ( IKeyBuilder keyBuilder in validationContext . KeyBuilders . Reverse ( ) )
313+ foreach ( IBodyModelValidatorKeyBuilder keyBuilder in validationContext . KeyBuilders . Reverse ( ) )
235314 {
236315 modelKey = keyBuilder . AppendTo ( modelKey ) ;
237316 }
@@ -263,7 +342,7 @@ private static Type GetElementType(Type type)
263342 return typeof ( object ) ;
264343 }
265344
266- private class PropertyScope : IKeyBuilder
345+ private class PropertyScope : IBodyModelValidatorKeyBuilder
267346 {
268347 public string PropertyName { get ; set ; }
269348
@@ -273,7 +352,7 @@ public string AppendTo(string prefix)
273352 }
274353 }
275354
276- private class ElementScope : IKeyBuilder
355+ private class ElementScope : IBodyModelValidatorKeyBuilder
277356 {
278357 public int Index { get ; set ; }
279358
@@ -282,16 +361,5 @@ public string AppendTo(string prefix)
282361 return ModelBindingHelper . CreateIndexModelName ( prefix , Index ) ;
283362 }
284363 }
285-
286- private class ValidationContext
287- {
288- public ModelMetadataProvider MetadataProvider { get ; set ; }
289- public HttpActionContext ActionContext { get ; set ; }
290- public IModelValidatorCache ValidatorCache { get ; set ; }
291- public ModelStateDictionary ModelState { get ; set ; }
292- public HashSet < object > Visited { get ; set ; }
293- public Stack < IKeyBuilder > KeyBuilders { get ; set ; }
294- public string RootPrefix { get ; set ; }
295- }
296364 }
297365}
0 commit comments