@@ -14,6 +14,9 @@ namespace Microsoft.AspNetCore.Http.Validation;
1414
1515internal static class ValidationEndpointFilterFactory
1616{
17+ // A small struct to hold the validatable parameter details to avoid allocating arrays for parameters that don't need validation
18+ private readonly record struct ValidatableParameterEntry ( int Index , IValidatableInfo Parameter , string DisplayName ) ;
19+
1720 public static EndpointFilterDelegate Create ( EndpointFilterFactoryContext context , EndpointFilterDelegate next )
1821 {
1922 var parameters = context . MethodInfo . GetParameters ( ) ;
@@ -25,12 +28,10 @@ public static EndpointFilterDelegate Create(EndpointFilterFactoryContext context
2528
2629 var serviceProviderIsService = context . ApplicationServices . GetService < IServiceProviderIsService > ( ) ;
2730
28- var parameterCount = parameters . Length ;
29- var validatableParameters = new IValidatableInfo [ parameterCount ] ;
30- var parameterDisplayNames = new string [ parameterCount ] ;
31- var hasValidatableParameters = false ;
31+ // Use a list to only store validatable parameters instead of arrays for all parameters
32+ List < ValidatableParameterEntry > ? validatableParameters = null ;
3233
33- for ( var i = 0 ; i < parameterCount ; i ++ )
34+ for ( var i = 0 ; i < parameters . Length ; i ++ )
3435 {
3536 // Ignore parameters that are resolved from the DI container.
3637 if ( IsServiceParameter ( parameters [ i ] , serviceProviderIsService ) )
@@ -40,13 +41,15 @@ public static EndpointFilterDelegate Create(EndpointFilterFactoryContext context
4041
4142 if ( options . TryGetValidatableParameterInfo ( parameters [ i ] , out var validatableParameter ) )
4243 {
43- validatableParameters [ i ] = validatableParameter ;
44- parameterDisplayNames [ i ] = GetDisplayName ( parameters [ i ] ) ;
45- hasValidatableParameters = true ;
44+ validatableParameters ??= [ ] ;
45+ validatableParameters . Add ( new ValidatableParameterEntry (
46+ i ,
47+ validatableParameter ,
48+ GetDisplayName ( parameters [ i ] ) ) ) ;
4649 }
4750 }
4851
49- if ( ! hasValidatableParameters )
52+ if ( validatableParameters is null || validatableParameters . Count == 0 )
5053 {
5154 return next ;
5255 }
@@ -55,18 +58,20 @@ public static EndpointFilterDelegate Create(EndpointFilterFactoryContext context
5558 {
5659 ValidateContext ? validateContext = null ;
5760
58- for ( var i = 0 ; i < context . Arguments . Count ; i ++ )
61+ foreach ( var entry in validatableParameters )
5962 {
60- var validatableParameter = validatableParameters [ i ] ;
61- var displayName = parameterDisplayNames [ i ] ;
63+ if ( entry . Index >= context . Arguments . Count )
64+ {
65+ break ;
66+ }
6267
63- var argument = context . Arguments [ i ] ;
64- if ( argument is null || validatableParameter is null )
68+ var argument = context . Arguments [ entry . Index ] ;
69+ if ( argument is null )
6570 {
6671 continue ;
6772 }
6873
69- var validationContext = new ValidationContext ( argument , displayName , context . HttpContext . RequestServices , items : null ) ;
74+ var validationContext = new ValidationContext ( argument , entry . DisplayName , context . HttpContext . RequestServices , items : null ) ;
7075
7176 if ( validateContext == null )
7277 {
@@ -81,7 +86,7 @@ public static EndpointFilterDelegate Create(EndpointFilterFactoryContext context
8186 validateContext . ValidationContext = validationContext ;
8287 }
8388
84- await validatableParameter . ValidateAsync ( argument , validateContext , context . HttpContext . RequestAborted ) ;
89+ await entry . Parameter . ValidateAsync ( argument , validateContext , context . HttpContext . RequestAborted ) ;
8590 }
8691
8792 if ( validateContext is { ValidationErrors . Count : > 0 } )
0 commit comments