44using System . Collections ;
55using System . ComponentModel . DataAnnotations ;
66using System . Diagnostics ;
7- using System . Linq ;
87
98namespace Microsoft . AspNetCore . Http . Validation ;
109
1110/// <summary>
1211/// Contains validation information for a parameter.
1312/// </summary>
14- public abstract class ValidatableParameterInfo
13+ public abstract class ValidatableParameterInfo : IValidatableInfo
1514{
16- private ValidationAttribute ? _requiredAttribute ;
15+ private RequiredAttribute ? _requiredAttribute ;
16+
1717 /// <summary>
1818 /// Creates a new instance of <see cref="ValidatableParameterInfo"/>.
1919 /// </summary>
2020 /// <param name="parameterType">The <see cref="Type"/> associated with the parameter.</param>
2121 /// <param name="name">The parameter name.</param>
2222 /// <param name="displayName">The display name for the parameter.</param>
23- /// <param name="isNullable">Whether the parameter is optional.</param>
24- /// <param name="isRequired"></param>
25- /// <param name="isEnumerable">Whether the parameter is enumerable.</param>
2623 public ValidatableParameterInfo (
2724 Type parameterType ,
2825 string name ,
29- string displayName ,
30- bool isNullable ,
31- bool isRequired ,
32- bool isEnumerable )
26+ string displayName )
3327 {
3428 ParameterType = parameterType ;
3529 Name = name ;
3630 DisplayName = displayName ;
37- IsNullable = isNullable ;
38- IsRequired = isRequired ;
39- IsEnumerable = isEnumerable ;
4031 }
4132
4233 /// <summary>
4334 /// Gets the parameter type.
4435 /// </summary>
45- public Type ParameterType { get ; }
36+ internal Type ParameterType { get ; }
4637
4738 /// <summary>
4839 /// Gets the parameter name.
4940 /// </summary>
50- public string Name { get ; }
41+ internal string Name { get ; }
5142
5243 /// <summary>
5344 /// Gets the display name for the parameter.
5445 /// </summary>
55- public string DisplayName { get ; }
56-
57- /// <summary>
58- /// Gets whether the parameter is optional.
59- /// </summary>
60- public bool IsNullable { get ; }
61-
62- /// <summary>
63- /// Gets whether the parameter is annotated with the <see cref="RequiredAttribute"/>.
64- /// </summary>
65- public bool IsRequired { get ; }
66-
67- /// <summary>
68- /// Gets whether the parameter is enumerable.
69- /// </summary>
70- public bool IsEnumerable { get ; }
46+ internal string DisplayName { get ; }
7147
7248 /// <summary>
7349 /// Gets the validation attributes for this parameter.
@@ -80,38 +56,36 @@ public ValidatableParameterInfo(
8056 /// </summary>
8157 /// <param name="value">The value to validate.</param>
8258 /// <param name="context">The context for the validation.</param>
59+ /// <param name="cancellationToken"></param>
8360 /// <returns>A task representing the asynchronous operation.</returns>
8461 /// <remarks>
8562 /// If the parameter is a collection, each item in the collection will be validated.
8663 /// If the parameter is not a collection but has a validatable type, the single value will be validated.
8764 /// </remarks>
88- public virtual Task Validate ( object ? value , ValidatableContext context )
65+ public virtual async ValueTask ValidateAsync ( object ? value , ValidatableContext context , CancellationToken cancellationToken )
8966 {
9067 Debug . Assert ( context . ValidationContext is not null ) ;
9168
9269 // Skip validation if value is null and parameter is optional
93- if ( value == null && IsNullable && ! IsRequired )
70+ if ( value == null && ParameterType . IsNullable ( ) )
9471 {
95- return Task . CompletedTask ;
72+ return ;
9673 }
9774
9875 context . ValidationContext . DisplayName = DisplayName ;
9976 context . ValidationContext . MemberName = Name ;
10077
10178 var validationAttributes = GetValidationAttributes ( ) ;
10279
103- if ( IsRequired )
80+ if ( _requiredAttribute is not null && validationAttributes . TryGetRequiredAttribute ( out _requiredAttribute ) )
10481 {
105- _requiredAttribute ??= validationAttributes . OfType < RequiredAttribute > ( )
106- . FirstOrDefault ( ) ;
107- Debug . Assert ( _requiredAttribute is not null , "RequiredAttribute should be present if IsRequired is true" ) ;
10882 var result = _requiredAttribute . GetValidationResult ( value , context . ValidationContext ) ;
10983
11084 if ( result is not null && result != ValidationResult . Success )
11185 {
11286 var key = string . IsNullOrEmpty ( context . Prefix ) ? Name : $ "{ context . Prefix } .{ Name } ";
11387 context . AddValidationError ( key , [ result . ErrorMessage ! ] ) ;
114- return Task . CompletedTask ;
88+ return ;
11589 }
11690 }
11791
@@ -136,7 +110,7 @@ public virtual Task Validate(object? value, ValidatableContext context)
136110 }
137111
138112 // If the parameter is a collection, validate each item
139- if ( IsEnumerable && value is IEnumerable enumerable )
113+ if ( ParameterType . IsEnumerable ( ) && value is IEnumerable enumerable )
140114 {
141115 var index = 0 ;
142116 foreach ( var item in enumerable )
@@ -149,7 +123,7 @@ public virtual Task Validate(object? value, ValidatableContext context)
149123
150124 if ( context . ValidationOptions . TryGetValidatableTypeInfo ( item . GetType ( ) , out var validatableType ) )
151125 {
152- validatableType . Validate ( item , context ) ;
126+ await validatableType . ValidateAsync ( item , context , cancellationToken ) ;
153127 }
154128 }
155129 index ++ ;
@@ -161,10 +135,8 @@ public virtual Task Validate(object? value, ValidatableContext context)
161135 var valueType = value . GetType ( ) ;
162136 if ( context . ValidationOptions . TryGetValidatableTypeInfo ( valueType , out var validatableType ) )
163137 {
164- validatableType . Validate ( value , context ) ;
138+ await validatableType . ValidateAsync ( value , context , cancellationToken ) ;
165139 }
166140 }
167-
168- return Task . CompletedTask ;
169141 }
170142}
0 commit comments