@@ -333,6 +333,11 @@ private static IReadOnlyList<object> AsReadOnlyList(IList<object> metadata)
333
333
// inference is skipped internally if necessary.
334
334
factoryContext . ArgumentExpressions ??= CreateArgumentsAndInferMetadata ( methodInfo , factoryContext ) ;
335
335
336
+ // Although we can re-use the cached argument expressions for most cases, parameters that are bound
337
+ // using the new form mapping logic are a special exception because we need to account for the `FormOptionsMetadata`
338
+ // added to the builder _during_ the construction of the parameter binding.
339
+ UpdateFormBindingArgumentExpressions ( factoryContext ) ;
340
+
336
341
factoryContext . MethodCall = CreateMethodCall ( methodInfo , targetExpression , factoryContext . ArgumentExpressions ) ;
337
342
EndpointFilterDelegate ? filterPipeline = null ;
338
343
var returnType = methodInfo . ReturnType ;
@@ -753,7 +758,7 @@ private static Expression CreateArgument(ParameterInfo parameter, RequestDelegat
753
758
( parameter . ParameterType . IsArray && ParameterBindingMethodCache . HasTryParseMethod ( parameter . ParameterType . GetElementType ( ) ! ) ) ;
754
759
return useSimpleBinding
755
760
? BindParameterFromFormItem ( parameter , formAttribute . Name ?? parameter . Name , factoryContext )
756
- : BindComplexParameterFromFormItem ( parameter , formAttribute . Name ?? parameter . Name , factoryContext ) ;
761
+ : BindComplexParameterFromFormItem ( parameter , string . IsNullOrEmpty ( formAttribute . Name ) ? parameter . Name : formAttribute . Name , factoryContext ) ;
757
762
}
758
763
else if ( parameter . CustomAttributes . Any ( a => typeof ( IFromServiceMetadata ) . IsAssignableFrom ( a . AttributeType ) ) )
759
764
{
@@ -1982,14 +1987,40 @@ private static Expression BindParameterFromFormItem(
1982
1987
"form" ) ;
1983
1988
}
1984
1989
1990
+ private static void UpdateFormBindingArgumentExpressions ( RequestDelegateFactoryContext factoryContext )
1991
+ {
1992
+ if ( factoryContext . ArgumentExpressions == null || factoryContext . ArgumentExpressions . Length == 0 )
1993
+ {
1994
+ return ;
1995
+ }
1996
+
1997
+ for ( var i = 0 ; i < factoryContext . ArgumentExpressions . Length ; i ++ )
1998
+ {
1999
+ var parameter = factoryContext . Parameters [ i ] ;
2000
+ var key = parameter . Name ! ;
2001
+ if ( factoryContext . TrackedParameters . TryGetValue ( key , out var trackedParameter ) && trackedParameter == RequestDelegateFactoryConstants . FormBindingAttribute )
2002
+ {
2003
+ factoryContext . ArgumentExpressions [ i ] = BindComplexParameterFromFormItem ( parameter , key , factoryContext ) ;
2004
+ }
2005
+ }
2006
+ }
2007
+
1985
2008
private static Expression BindComplexParameterFromFormItem (
1986
2009
ParameterInfo parameter ,
1987
2010
string key ,
1988
2011
RequestDelegateFactoryContext factoryContext )
1989
2012
{
1990
2013
factoryContext . FirstFormRequestBodyParameter ??= parameter ;
1991
- factoryContext . TrackedParameters . Add ( key , RequestDelegateFactoryConstants . FormAttribute ) ;
2014
+ factoryContext . TrackedParameters . TryAdd ( key , RequestDelegateFactoryConstants . FormBindingAttribute ) ;
1992
2015
factoryContext . ReadForm = true ;
2016
+ var formDataMapperOptions = FormDataMapperOptions ;
2017
+ var formMappingOptionsMetadatas = factoryContext . EndpointBuilder . Metadata . OfType < FormMappingOptionsMetadata > ( ) ;
2018
+ foreach ( var formMappingOptionsMetadata in formMappingOptionsMetadatas )
2019
+ {
2020
+ formDataMapperOptions . MaxRecursionDepth = formMappingOptionsMetadata . MaxRecursionDepth ?? formDataMapperOptions . MaxRecursionDepth ;
2021
+ formDataMapperOptions . MaxCollectionSize = formMappingOptionsMetadata . MaxCollectionSize ?? formDataMapperOptions . MaxCollectionSize ;
2022
+ formDataMapperOptions . MaxKeyBufferSize = formMappingOptionsMetadata . MaxKeySize ?? formDataMapperOptions . MaxKeyBufferSize ;
2023
+ }
1993
2024
1994
2025
// var name_local;
1995
2026
// var name_reader;
@@ -2001,19 +2032,19 @@ private static Expression BindComplexParameterFromFormItem(
2001
2032
var formBuffer = Expression . Variable ( typeof ( char [ ] ) , "form_buffer" ) ;
2002
2033
2003
2034
// ProcessForm(context.Request.Form, form_dict, form_buffer);
2004
- var processFormExpr = Expression . Call ( ProcessFormMethod , FormExpr , formDict , formBuffer ) ;
2035
+ var processFormExpr = Expression . Call ( ProcessFormMethod , FormExpr , Expression . Constant ( formDataMapperOptions . MaxKeyBufferSize ) , formDict , formBuffer ) ;
2005
2036
// name_reader = new FormDataReader(form_dict, CultureInfo.InvariantCulture, form_buffer.AsMemory(0, FormDataMapperOptions.MaxKeyBufferSize));
2006
2037
var initializeReaderExpr = Expression . Assign (
2007
2038
formReader ,
2008
2039
Expression . New ( FormDataReaderConstructor ,
2009
2040
formDict ,
2010
2041
Expression . Constant ( CultureInfo . InvariantCulture ) ,
2011
- Expression . Call ( AsMemoryMethod , formBuffer , Expression . Constant ( 0 ) , Expression . Constant ( FormDataMapperOptions . MaxKeyBufferSize ) ) ) ) ;
2042
+ Expression . Call ( AsMemoryMethod , formBuffer , Expression . Constant ( 0 ) , Expression . Constant ( formDataMapperOptions . MaxKeyBufferSize ) ) ) ) ;
2012
2043
// FormDataMapper.Map<string>(name_reader, FormDataMapperOptions);
2013
2044
var invokeMapMethodExpr = Expression . Call (
2014
2045
FormDataMapperMapMethod . MakeGenericMethod ( parameter . ParameterType ) ,
2015
2046
formReader ,
2016
- Expression . Constant ( FormDataMapperOptions ) ) ;
2047
+ Expression . Constant ( formDataMapperOptions ) ) ;
2017
2048
// if (form_buffer != null)
2018
2049
// {
2019
2050
// ArrayPool<char>.Shared.Return(form_buffer, false);
@@ -2039,15 +2070,15 @@ private static Expression BindComplexParameterFromFormItem(
2039
2070
) ;
2040
2071
}
2041
2072
2042
- private static void ProcessForm ( IFormCollection form , ref IReadOnlyDictionary < FormKey , StringValues > formDictionary , ref char [ ] buffer )
2073
+ private static void ProcessForm ( IFormCollection form , int maxKeyBufferSize , ref IReadOnlyDictionary < FormKey , StringValues > formDictionary , ref char [ ] buffer )
2043
2074
{
2044
2075
var dictionary = new Dictionary < FormKey , StringValues > ( ) ;
2045
2076
foreach ( var ( key , value ) in form )
2046
2077
{
2047
2078
dictionary . Add ( new FormKey ( key . AsMemory ( ) ) , value ) ;
2048
2079
}
2049
2080
formDictionary = dictionary . AsReadOnly ( ) ;
2050
- buffer = ArrayPool < char > . Shared . Rent ( FormDataMapperOptions . MaxKeyBufferSize ) ;
2081
+ buffer = ArrayPool < char > . Shared . Rent ( maxKeyBufferSize ) ;
2051
2082
}
2052
2083
2053
2084
private static Expression BindParameterFromFormFiles (
@@ -2447,6 +2478,7 @@ private static class RequestDelegateFactoryConstants
2447
2478
public const string ServiceAttribute = "Service (Attribute)" ;
2448
2479
public const string FormFileAttribute = "Form File (Attribute)" ;
2449
2480
public const string FormAttribute = "Form (Attribute)" ;
2481
+ public const string FormBindingAttribute = "Form Binding (Attribute)" ;
2450
2482
public const string RouteParameter = "Route (Inferred)" ;
2451
2483
public const string QueryStringParameter = "Query String (Inferred)" ;
2452
2484
public const string ServiceParameter = "Services (Inferred)" ;
0 commit comments