16
16
namespace System . Web . Http . Validation
17
17
{
18
18
/// <summary>
19
- /// Recursively validate an object.
19
+ /// Recursively validate an object.
20
20
/// </summary>
21
21
public class DefaultBodyModelValidator : IBodyModelValidator
22
22
{
23
- private interface IKeyBuilder
24
- {
25
- string AppendTo ( string prefix ) ;
26
- }
27
-
28
23
/// <summary>
29
24
/// Determines whether the <paramref name="model"/> is valid and adds any validation errors to the <paramref name="actionContext"/>'s <see cref="ModelStateDictionary"/>
30
25
/// </summary>
@@ -64,14 +59,14 @@ public bool Validate(object model, Type type, ModelMetadataProvider metadataProv
64
59
}
65
60
66
61
ModelMetadata metadata = metadataProvider . GetMetadataForType ( ( ) => model , type ) ;
67
- ValidationContext validationContext = new ValidationContext ( )
62
+ BodyModelValidatorContext validationContext = new BodyModelValidatorContext
68
63
{
69
64
MetadataProvider = metadataProvider ,
70
65
ActionContext = actionContext ,
71
66
ValidatorCache = actionContext . GetValidatorCache ( ) ,
72
67
ModelState = actionContext . ModelState ,
73
68
Visited = new HashSet < object > ( ReferenceEqualityComparer . Instance ) ,
74
- KeyBuilders = new Stack < IKeyBuilder > ( ) ,
69
+ KeyBuilders = new Stack < IBodyModelValidatorKeyBuilder > ( ) ,
75
70
RootPrefix = keyPrefix
76
71
} ;
77
72
return ValidateNodeAndChildren ( metadata , validationContext , container : null , validators : null ) ;
@@ -87,12 +82,36 @@ public virtual bool ShouldValidateType(Type type)
87
82
return ! MediaTypeFormatterCollection . IsTypeExcludedFromValidation ( type ) ;
88
83
}
89
84
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>
90
96
[ 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 )
92
102
{
93
103
// Recursion guard to avoid stack overflows
94
104
RuntimeHelpers . EnsureSufficientExecutionStack ( ) ;
95
105
106
+ if ( metadata == null )
107
+ {
108
+ throw Error . ArgumentNull ( "metadata" ) ;
109
+ }
110
+ if ( validationContext == null )
111
+ {
112
+ throw Error . ArgumentNull ( "validationContext" ) ;
113
+ }
114
+
96
115
object model = null ;
97
116
try
98
117
{
@@ -155,8 +174,26 @@ private bool ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext v
155
174
return isValid ;
156
175
}
157
176
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 )
159
187
{
188
+ if ( metadata == null )
189
+ {
190
+ throw Error . ArgumentNull ( "metadata" ) ;
191
+ }
192
+ if ( validationContext == null )
193
+ {
194
+ throw Error . ArgumentNull ( "validationContext" ) ;
195
+ }
196
+
160
197
bool isValid = true ;
161
198
PropertyScope propertyScope = new PropertyScope ( ) ;
162
199
validationContext . KeyBuilders . Push ( propertyScope ) ;
@@ -172,8 +209,26 @@ private bool ValidateProperties(ModelMetadata metadata, ValidationContext valida
172
209
return isValid ;
173
210
}
174
211
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 )
176
222
{
223
+ if ( model == null )
224
+ {
225
+ throw Error . ArgumentNull ( "model" ) ;
226
+ }
227
+ if ( validationContext == null )
228
+ {
229
+ throw Error . ArgumentNull ( "validationContext" ) ;
230
+ }
231
+
177
232
bool isValid = true ;
178
233
Type elementType = GetElementType ( model . GetType ( ) ) ;
179
234
ModelMetadata elementMetadata = validationContext . MetadataProvider . GetMetadataForType ( null , elementType ) ;
@@ -207,15 +262,39 @@ private bool ValidateElements(IEnumerable model, ValidationContext validationCon
207
262
return isValid ;
208
263
}
209
264
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 )
213
281
{
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
+
214
295
bool isValid = true ;
215
296
string modelKey = null ;
216
297
217
- Contract . Assert ( validators != null ) ;
218
-
219
298
// When the are no validators we bail quickly. This saves a GetEnumerator allocation.
220
299
// In a large array (tens of thousands or more) scenario it's very significant.
221
300
ICollection validatorsAsCollection = validators as ICollection ;
@@ -231,7 +310,7 @@ private static bool ShallowValidate(ModelMetadata metadata, ValidationContext va
231
310
if ( modelKey == null )
232
311
{
233
312
modelKey = validationContext . RootPrefix ;
234
- foreach ( IKeyBuilder keyBuilder in validationContext . KeyBuilders . Reverse ( ) )
313
+ foreach ( IBodyModelValidatorKeyBuilder keyBuilder in validationContext . KeyBuilders . Reverse ( ) )
235
314
{
236
315
modelKey = keyBuilder . AppendTo ( modelKey ) ;
237
316
}
@@ -263,7 +342,7 @@ private static Type GetElementType(Type type)
263
342
return typeof ( object ) ;
264
343
}
265
344
266
- private class PropertyScope : IKeyBuilder
345
+ private class PropertyScope : IBodyModelValidatorKeyBuilder
267
346
{
268
347
public string PropertyName { get ; set ; }
269
348
@@ -273,7 +352,7 @@ public string AppendTo(string prefix)
273
352
}
274
353
}
275
354
276
- private class ElementScope : IKeyBuilder
355
+ private class ElementScope : IBodyModelValidatorKeyBuilder
277
356
{
278
357
public int Index { get ; set ; }
279
358
@@ -282,16 +361,5 @@ public string AppendTo(string prefix)
282
361
return ModelBindingHelper . CreateIndexModelName ( prefix , Index ) ;
283
362
}
284
363
}
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
- }
296
364
}
297
365
}
0 commit comments