@@ -40,6 +40,7 @@ public static class RequestDelegateFactory
40
40
private static readonly ParameterExpression HttpContextExpr = Expression . Parameter ( typeof ( HttpContext ) , "httpContext" ) ;
41
41
private static readonly ParameterExpression BodyValueExpr = Expression . Parameter ( typeof ( object ) , "bodyValue" ) ;
42
42
private static readonly ParameterExpression WasTryParseFailureExpr = Expression . Variable ( typeof ( bool ) , "wasTryParseFailure" ) ;
43
+ private static readonly ParameterExpression TempSourceStringExpr = Expression . Variable ( typeof ( string ) , "tempSourceString" ) ;
43
44
44
45
private static readonly MemberExpression RequestServicesExpr = Expression . Property ( HttpContextExpr , nameof ( HttpContext . RequestServices ) ) ;
45
46
private static readonly MemberExpression HttpRequestExpr = Expression . Property ( HttpContextExpr , nameof ( HttpContext . Request ) ) ;
@@ -277,23 +278,30 @@ private static Expression CreateResponseWritingMethodCall(MethodInfo methodInfo,
277
278
// If we're calling TryParse and the WasTryParseFailureVariable indicates it failed, set a 400 StatusCode instead of calling the method.
278
279
private static Expression CreateTryParseCheckingResponseWritingMethodCall ( MethodInfo methodInfo , Expression ? target , Expression [ ] arguments )
279
280
{
281
+
280
282
// {
281
- // bool wasTryParseFailure = false;
283
+ // bool wasTryParseFailureVariable = false;
284
+ // string tempSourceString;
282
285
//
283
286
// // Assume "[FromRoute] int id" is the first parameter.
284
- // int param1 = httpContext.Request.RouteValue["id"] == null ? default :
287
+ //
288
+ // tempSourceString = httpContext.RequestValue["id"];
289
+ //
290
+ // int param1 = tempSourceString == null ? default :
285
291
// {
286
- // var sourceValue = httpContext.Request.RouteValue["id"];
287
292
// int parsedValue = default;
288
293
//
289
- // if (!int.TryParse(sourceValue , out parsedValue))
294
+ // if (!int.TryParse(tempSourceString , out parsedValue))
290
295
// {
291
- // wasTryParseFailure = true;
296
+ // wasTryParseFailureVariable = true;
292
297
// Log.ParameterBindingFailed(httpContext, "Int32", "id", sourceValue)
293
298
// }
294
299
//
295
300
// return parsedValue;
296
301
// };
302
+ //
303
+ // tempSourceString = httpContext.RequestValue["param2"];
304
+ // int param2 = tempSourceString == null ? default :
297
305
// // ...
298
306
//
299
307
// return wasTryParseFailure ?
@@ -302,20 +310,21 @@ private static Expression CreateTryParseCheckingResponseWritingMethodCall(Method
302
310
// return Task.CompletedTask;
303
311
// } :
304
312
// {
305
- // // Logic generated by AddResponseWritingToMethodCall() that calls action(param1, ...)
313
+ // // Logic generated by AddResponseWritingToMethodCall() that calls action(param1, parm2, ...)
306
314
// };
307
315
// }
308
316
309
317
var parameters = methodInfo . GetParameters ( ) ;
310
318
var storedArguments = new ParameterExpression [ parameters . Length ] ;
311
- var localVariables = new ParameterExpression [ parameters . Length + 1 ] ;
319
+ var localVariables = new ParameterExpression [ parameters . Length + 2 ] ;
312
320
313
321
for ( var i = 0 ; i < parameters . Length ; i ++ )
314
322
{
315
323
storedArguments [ i ] = localVariables [ i ] = Expression . Parameter ( parameters [ i ] . ParameterType ) ;
316
324
}
317
325
318
326
localVariables [ parameters . Length ] = WasTryParseFailureExpr ;
327
+ localVariables [ parameters . Length + 1 ] = TempSourceStringExpr ;
319
328
320
329
var assignAndCall = new Expression [ parameters . Length + 1 ] ;
321
330
for ( var i = 0 ; i < parameters . Length ; i ++ )
@@ -592,74 +601,79 @@ private static Expression GetValueFromProperty(Expression sourceExpression, stri
592
601
593
602
private static Expression BindParameterFromValue ( ParameterInfo parameter , Expression valueExpression , FactoryContext factoryContext )
594
603
{
595
- Expression argumentExpression ;
596
-
597
604
if ( parameter . ParameterType == typeof ( string ) )
598
605
{
599
- argumentExpression = valueExpression ;
606
+ return valueExpression ;
600
607
}
601
- else
602
- {
603
- var nonNullableParameterType = Nullable . GetUnderlyingType ( parameter . ParameterType ) ?? parameter . ParameterType ;
604
- var tryParseMethod = FindTryParseMethod ( nonNullableParameterType ) ;
605
608
606
- if ( tryParseMethod is null )
607
- {
608
- throw new InvalidOperationException ( $ "No public static bool { parameter . ParameterType . Name } .TryParse(string, out { parameter . ParameterType . Name } ) method found for { parameter . Name } .") ;
609
- }
609
+ var underlyingNullableType = Nullable . GetUnderlyingType ( parameter . ParameterType ) ;
610
+ var nonNullableParameterType = underlyingNullableType ?? parameter . ParameterType ;
611
+ var tryParseMethod = FindTryParseMethod ( nonNullableParameterType ) ;
612
+
613
+ if ( tryParseMethod is null )
614
+ {
615
+ throw new InvalidOperationException ( $ "No public static bool { parameter . ParameterType . Name } .TryParse(string, out { parameter . ParameterType . Name } ) method found for { parameter . Name } .") ;
616
+ }
610
617
611
- // bool wasTryParseFailureVariable = false;
612
- //
613
- // // Assume "[FromRoute] int id" is the first parameter.
614
- // int param1 = httpContext.Request.RouteValue["id"] == null ? default :
615
- // {
616
- // var sourceValue = httpContext.Request.RouteValue["id"];
617
- // int parsedValue = default;
618
- //
619
- // if (!int.TryParse(sourceValue, out parsedValue))
620
- // {
621
- // wasTryParseFailureVariable = true;
622
- // Log.ParameterBindingFailed(httpContext, "Int32", "id", sourceValue)
623
- // }
624
- //
625
- // return parsedValue;
626
- // };
618
+ // bool wasTryParseFailureVariable = false;
619
+ // string tempSourceString;
620
+ //
621
+ // // Assume "[FromRoute] int id" is the first parameter.
622
+ //
623
+ // tempSourceString = httpContext.RequestValue["id"];
624
+ //
625
+ // int param1 = tempSourceString == null ? default :
626
+ // {
627
+ // int parsedValue = default;
628
+ //
629
+ // if (!int.TryParse(tempSourceString, out parsedValue))
630
+ // {
631
+ // wasTryParseFailureVariable = true;
632
+ // Log.ParameterBindingFailed(httpContext, "Int32", "id", sourceValue)
633
+ // }
634
+ //
635
+ // return parsedValue;
636
+ // };
627
637
628
- factoryContext . CheckForTryParseFailure = true ;
638
+ factoryContext . CheckForTryParseFailure = true ;
629
639
630
- var parsedValue = Expression . Variable ( nonNullableParameterType ) ;
640
+ var parsedValue = Expression . Variable ( nonNullableParameterType ) ;
631
641
632
- var tryParseCall = Expression . Call ( tryParseMethod , valueExpression , parsedValue ) ;
642
+ var parameterTypeNameConstant = Expression . Constant ( parameter . ParameterType . Name ) ;
643
+ var parameterNameConstant = Expression . Constant ( parameter . Name ) ;
633
644
634
- var parameterTypeConstant = Expression . Constant ( nonNullableParameterType . Name ) ;
635
- var parameterNameConstant = Expression . Constant ( parameter . Name ) ;
636
- var failBlock = Expression . Block (
637
- Expression . Assign ( WasTryParseFailureExpr , Expression . Constant ( true ) ) ,
638
- Expression . Call ( LogParameterBindingFailureMethod ,
639
- HttpContextExpr , parameterTypeConstant , parameterNameConstant , valueExpression ) ) ;
645
+ var failBlock = Expression . Block (
646
+ Expression . Assign ( WasTryParseFailureExpr , Expression . Constant ( true ) ) ,
647
+ Expression . Call ( LogParameterBindingFailureMethod ,
648
+ HttpContextExpr , parameterTypeNameConstant , parameterNameConstant , TempSourceStringExpr ) ) ;
640
649
641
- var ifFailExpression = Expression . IfThen ( Expression . Not ( tryParseCall ) , failBlock ) ;
650
+ var tryParseCall = Expression . Call ( tryParseMethod , TempSourceStringExpr , parsedValue ) ;
651
+ var ifFailExpression = Expression . IfThen ( Expression . Not ( tryParseCall ) , failBlock ) ;
642
652
643
- argumentExpression = Expression . Block ( new [ ] { parsedValue } ,
644
- ifFailExpression ,
645
- parsedValue ) ;
646
- }
653
+ Expression parsedValueExpression = Expression . Block ( new [ ] { parsedValue } ,
654
+ ifFailExpression ,
655
+ parsedValue ) ;
647
656
648
- // Convert to nullable if necessary.
649
- if ( argumentExpression . Type != parameter . ParameterType )
657
+ // Convert back to nullable if necessary.
658
+ if ( underlyingNullableType is not null )
650
659
{
651
- argumentExpression = Expression . Convert ( argumentExpression , parameter . ParameterType ) ;
660
+ parsedValueExpression = Expression . Convert ( parsedValueExpression , parameter . ParameterType ) ;
652
661
}
653
662
654
663
Expression defaultExpression = parameter . HasDefaultValue ?
655
664
Expression . Constant ( parameter . DefaultValue ) :
656
665
Expression . Default ( parameter . ParameterType ) ;
657
666
658
- // int param1 = httpContext.Request.RouteValue["id"] == null ? default : ...
659
- return Expression . Condition (
660
- Expression . Equal ( valueExpression , Expression . Constant ( null ) ) ,
667
+ // tempSourceString = httpContext.RequestValue["id];
668
+ var storeValueToTemp = Expression . Assign ( TempSourceStringExpr , valueExpression ) ;
669
+
670
+ // int param1 = tempSourcString == null ? default : ...
671
+ var ternary = Expression . Condition (
672
+ Expression . Equal ( TempSourceStringExpr , Expression . Constant ( null ) ) ,
661
673
defaultExpression ,
662
- argumentExpression ) ;
674
+ parsedValueExpression ) ;
675
+
676
+ return Expression . Block ( storeValueToTemp , ternary ) ;
663
677
}
664
678
665
679
private static Expression BindParameterFromProperty ( ParameterInfo parameter , MemberExpression property , string key , FactoryContext factoryContext ) =>
@@ -828,9 +842,9 @@ public static void RequestBodyInvalidDataException(HttpContext httpContext, Inva
828
842
_requestBodyInvalidDataException ( GetLogger ( httpContext ) , exception ) ;
829
843
}
830
844
831
- public static void ParameterBindingFailed ( HttpContext httpContext , string parameterType , string parameterName , string sourceValue )
845
+ public static void ParameterBindingFailed ( HttpContext httpContext , string parameterTypeName , string parameterName , string sourceValue )
832
846
{
833
- _parameterBindingFailed ( GetLogger ( httpContext ) , parameterType , parameterName , sourceValue , null ) ;
847
+ _parameterBindingFailed ( GetLogger ( httpContext ) , parameterTypeName , parameterName , sourceValue , null ) ;
834
848
}
835
849
836
850
private static ILogger GetLogger ( HttpContext httpContext )
0 commit comments