@@ -24,7 +24,8 @@ internal static class MapActionExpressionTreeBuilder
24
24
private static readonly MethodInfo ChangeTypeMethodInfo = GetMethodInfo < Func < object , Type , object > > ( ( value , type ) => Convert . ChangeType ( value , type , CultureInfo . InvariantCulture ) ) ;
25
25
private static readonly MethodInfo ExecuteTaskOfTMethodInfo = typeof ( MapActionExpressionTreeBuilder ) . GetMethod ( nameof ( ExecuteTask ) , BindingFlags . NonPublic | BindingFlags . Static ) ! ;
26
26
private static readonly MethodInfo ExecuteTaskOfStringMethodInfo = typeof ( MapActionExpressionTreeBuilder ) . GetMethod ( nameof ( ExecuteTaskOfString ) , BindingFlags . NonPublic | BindingFlags . Static ) ! ;
27
- private static readonly MethodInfo ExecuteValueTaskOfTMethodInfo = typeof ( MapActionExpressionTreeBuilder ) . GetMethod ( nameof ( ExecuteValueTask ) , BindingFlags . NonPublic | BindingFlags . Static ) ! ;
27
+ private static readonly MethodInfo ExecuteValueTaskOfTMethodInfo = typeof ( MapActionExpressionTreeBuilder ) . GetMethod ( nameof ( ExecuteValueTaskOfT ) , BindingFlags . NonPublic | BindingFlags . Static ) ! ;
28
+ private static readonly MethodInfo ExecuteValueTaskMethodInfo = typeof ( MapActionExpressionTreeBuilder ) . GetMethod ( nameof ( ExecuteValueTask ) , BindingFlags . NonPublic | BindingFlags . Static ) ! ;
28
29
private static readonly MethodInfo ExecuteValueTaskOfStringMethodInfo = typeof ( MapActionExpressionTreeBuilder ) . GetMethod ( nameof ( ExecuteValueTaskOfString ) , BindingFlags . NonPublic | BindingFlags . Static ) ! ;
29
30
private static readonly MethodInfo ExecuteTaskResultOfTMethodInfo = typeof ( MapActionExpressionTreeBuilder ) . GetMethod ( nameof ( ExecuteTaskResult ) , BindingFlags . NonPublic | BindingFlags . Static ) ! ;
30
31
private static readonly MethodInfo ExecuteValueResultTaskOfTMethodInfo = typeof ( MapActionExpressionTreeBuilder ) . GetMethod ( nameof ( ExecuteValueTaskResult ) , BindingFlags . NonPublic | BindingFlags . Static ) ! ;
@@ -71,28 +72,31 @@ public static RequestDelegate BuildRequestDelegate(Delegate action)
71
72
// This argument represents the deserialized body returned from IHttpRequestReader
72
73
// when the method has a FromBody attribute declared
73
74
74
- var args = new List < Expression > ( ) ;
75
+ var methodParameters = method . GetParameters ( ) ;
76
+ var args = new List < Expression > ( methodParameters . Length ) ;
75
77
76
- foreach ( var parameter in method . GetParameters ( ) )
78
+ foreach ( var parameter in methodParameters )
77
79
{
78
80
Expression paramterExpression = Expression . Default ( parameter . ParameterType ) ;
79
81
80
- if ( parameter . GetCustomAttributes ( ) . OfType < IFromRouteMetadata > ( ) . FirstOrDefault ( ) is { } routeAttribute )
82
+ var parameterCustomAttributes = parameter . GetCustomAttributes ( ) ;
83
+
84
+ if ( parameterCustomAttributes . OfType < IFromRouteMetadata > ( ) . FirstOrDefault ( ) is { } routeAttribute )
81
85
{
82
86
var routeValuesProperty = Expression . Property ( HttpRequestExpr , nameof ( HttpRequest . RouteValues ) ) ;
83
87
paramterExpression = BindParamenter ( routeValuesProperty , parameter , routeAttribute . Name ) ;
84
88
}
85
- else if ( parameter . GetCustomAttributes ( ) . OfType < IFromQueryMetadata > ( ) . FirstOrDefault ( ) is { } queryAttribute )
89
+ else if ( parameterCustomAttributes . OfType < IFromQueryMetadata > ( ) . FirstOrDefault ( ) is { } queryAttribute )
86
90
{
87
91
var queryProperty = Expression . Property ( HttpRequestExpr , nameof ( HttpRequest . Query ) ) ;
88
92
paramterExpression = BindParamenter ( queryProperty , parameter , queryAttribute . Name ) ;
89
93
}
90
- else if ( parameter . GetCustomAttributes ( ) . OfType < IFromHeaderMetadata > ( ) . FirstOrDefault ( ) is { } headerAttribute )
94
+ else if ( parameterCustomAttributes . OfType < IFromHeaderMetadata > ( ) . FirstOrDefault ( ) is { } headerAttribute )
91
95
{
92
96
var headersProperty = Expression . Property ( HttpRequestExpr , nameof ( HttpRequest . Headers ) ) ;
93
97
paramterExpression = BindParamenter ( headersProperty , parameter , headerAttribute . Name ) ;
94
98
}
95
- else if ( parameter . GetCustomAttributes ( ) . OfType < IFromBodyMetadata > ( ) . FirstOrDefault ( ) is { } bodyAttribute )
99
+ else if ( parameterCustomAttributes . OfType < IFromBodyMetadata > ( ) . FirstOrDefault ( ) is { } bodyAttribute )
96
100
{
97
101
if ( consumeBodyDirectly )
98
102
{
@@ -109,7 +113,7 @@ public static RequestDelegate BuildRequestDelegate(Delegate action)
109
113
bodyType = parameter . ParameterType ;
110
114
paramterExpression = Expression . Convert ( DeserializedBodyArg , bodyType ) ;
111
115
}
112
- else if ( parameter . GetCustomAttributes ( ) . OfType < IFromFormMetadata > ( ) . FirstOrDefault ( ) is { } formAttribute )
116
+ else if ( parameterCustomAttributes . OfType < IFromFormMetadata > ( ) . FirstOrDefault ( ) is { } formAttribute )
113
117
{
114
118
if ( consumeBodyDirectly )
115
119
{
@@ -125,27 +129,24 @@ public static RequestDelegate BuildRequestDelegate(Delegate action)
125
129
{
126
130
paramterExpression = Expression . Call ( GetRequiredServiceMethodInfo . MakeGenericMethod ( parameter . ParameterType ) , RequestServicesExpr ) ;
127
131
}
128
- else
132
+ else if ( parameter . ParameterType == typeof ( IFormCollection ) )
129
133
{
130
- if ( parameter . ParameterType == typeof ( IFormCollection ) )
134
+ if ( consumeBodyDirectly )
131
135
{
132
- if ( consumeBodyDirectly )
133
- {
134
- ThrowCannotReadBodyDirectlyAndAsForm ( ) ;
135
- }
136
+ ThrowCannotReadBodyDirectlyAndAsForm ( ) ;
137
+ }
136
138
137
- consumeBodyAsForm = true ;
139
+ consumeBodyAsForm = true ;
138
140
139
- paramterExpression = Expression . Property ( HttpRequestExpr , nameof ( HttpRequest . Form ) ) ;
140
- }
141
- else if ( parameter . ParameterType == typeof ( HttpContext ) )
142
- {
143
- paramterExpression = HttpContextParameter ;
144
- }
145
- else if ( parameter . ParameterType == typeof ( CancellationToken ) )
146
- {
147
- paramterExpression = RequestAbortedExpr ;
148
- }
141
+ paramterExpression = Expression . Property ( HttpRequestExpr , nameof ( HttpRequest . Form ) ) ;
142
+ }
143
+ else if ( parameter . ParameterType == typeof ( HttpContext ) )
144
+ {
145
+ paramterExpression = HttpContextParameter ;
146
+ }
147
+ else if ( parameter . ParameterType == typeof ( CancellationToken ) )
148
+ {
149
+ paramterExpression = RequestAbortedExpr ;
149
150
}
150
151
151
152
args . Add ( paramterExpression ) ;
@@ -182,6 +183,12 @@ public static RequestDelegate BuildRequestDelegate(Delegate action)
182
183
{
183
184
body = methodCall ;
184
185
}
186
+ else if ( method . ReturnType == typeof ( ValueTask ) )
187
+ {
188
+ body = Expression . Call (
189
+ ExecuteValueTaskMethodInfo ,
190
+ methodCall ) ;
191
+ }
185
192
else if ( method . ReturnType . IsGenericType &&
186
193
method . ReturnType . GetGenericTypeDefinition ( ) == typeof ( Task < > ) )
187
194
{
@@ -263,7 +270,7 @@ public static RequestDelegate BuildRequestDelegate(Delegate action)
263
270
var box = Expression . TypeAs ( methodCall , typeof ( object ) ) ;
264
271
body = Expression . Call ( JsonResultWriteResponseAsync , HttpResponseExpr , box , Expression . Constant ( CancellationToken . None ) ) ;
265
272
}
266
- else
273
+ else
267
274
{
268
275
body = Expression . Call ( JsonResultWriteResponseAsync , HttpResponseExpr , methodCall , Expression . Constant ( CancellationToken . None ) ) ;
269
276
}
@@ -398,10 +405,20 @@ private static Expression BindParamenter(Expression sourceExpression, ParameterI
398
405
expr = Expression . Convert ( expr , parameter . ParameterType ) ;
399
406
}
400
407
408
+ Expression defaultExpression ;
409
+ if ( parameter . HasDefaultValue )
410
+ {
411
+ defaultExpression = Expression . Constant ( parameter . DefaultValue ) ;
412
+ }
413
+ else
414
+ {
415
+ defaultExpression = Expression . Default ( parameter . ParameterType ) ;
416
+ }
417
+
401
418
// property[key] == null ? default : (ParameterType){Type}.Parse(property[key]);
402
419
expr = Expression . Condition (
403
420
Expression . Equal ( valueArg , Expression . Constant ( null ) ) ,
404
- Expression . Default ( parameter . ParameterType ) ,
421
+ defaultExpression ,
405
422
expr ) ;
406
423
407
424
return expr ;
@@ -449,7 +466,22 @@ static async Task ExecuteAwaited(Task<string> task, HttpContext httpContext)
449
466
return ExecuteAwaited ( task , httpContext ) ;
450
467
}
451
468
452
- private static Task ExecuteValueTask < T > ( ValueTask < T > task , HttpContext httpContext )
469
+ private static Task ExecuteValueTask ( ValueTask task )
470
+ {
471
+ static async Task ExecuteAwaited ( ValueTask task )
472
+ {
473
+ await task ;
474
+ }
475
+
476
+ if ( task . IsCompletedSuccessfully )
477
+ {
478
+ task . GetAwaiter ( ) . GetResult ( ) ;
479
+ }
480
+
481
+ return ExecuteAwaited ( task ) ;
482
+ }
483
+
484
+ private static Task ExecuteValueTaskOfT < T > ( ValueTask < T > task , HttpContext httpContext )
453
485
{
454
486
static async Task ExecuteAwaited ( ValueTask < T > task , HttpContext httpContext )
455
487
{
0 commit comments