@@ -60,9 +60,11 @@ public static partial class RequestDelegateFactory
60
60
/// Creates a <see cref="RequestDelegate"/> implementation for <paramref name="action"/>.
61
61
/// </summary>
62
62
/// <param name="action">A request handler with any number of custom parameters that often produces a response with its return value.</param>
63
- /// <param name="serviceProvider ">The <see cref="IServiceProvider "/> instance used to detect which parameters are services .</param>
63
+ /// <param name="options ">The <see cref="RequestDelegateFactoryOptions "/> used to configure the behavior of the handler .</param>
64
64
/// <returns>The <see cref="RequestDelegate"/>.</returns>
65
- public static RequestDelegate Create ( Delegate action , IServiceProvider ? serviceProvider )
65
+ #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters
66
+ public static RequestDelegate Create ( Delegate action , RequestDelegateFactoryOptions ? options = null )
67
+ #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters
66
68
{
67
69
if ( action is null )
68
70
{
@@ -75,69 +77,60 @@ public static RequestDelegate Create(Delegate action, IServiceProvider? serviceP
75
77
null => null ,
76
78
} ;
77
79
78
- var targetableRequestDelegate = CreateTargetableRequestDelegate ( action . Method , serviceProvider , targetExpression ) ;
80
+ var targetableRequestDelegate = CreateTargetableRequestDelegate ( action . Method , options , targetExpression ) ;
79
81
80
82
return httpContext =>
81
83
{
82
84
return targetableRequestDelegate ( action . Target , httpContext ) ;
83
85
} ;
84
86
}
85
87
86
- /// <summary>
87
- /// Creates a <see cref="RequestDelegate"/> implementation for <paramref name="methodInfo"/>.
88
- /// </summary>
89
- /// <param name="methodInfo">A static request handler with any number of custom parameters that often produces a response with its return value.</param>
90
- /// <param name="serviceProvider">The <see cref="IServiceProvider"/> instance used to detect which parameters are services.</param>
91
- /// <returns>The <see cref="RequestDelegate"/>.</returns>
92
- public static RequestDelegate Create ( MethodInfo methodInfo , IServiceProvider ? serviceProvider )
93
- {
94
- if ( methodInfo is null )
95
- {
96
- throw new ArgumentNullException ( nameof ( methodInfo ) ) ;
97
- }
98
-
99
- var targetableRequestDelegate = CreateTargetableRequestDelegate ( methodInfo , serviceProvider , targetExpression : null ) ;
100
-
101
- return httpContext =>
102
- {
103
- return targetableRequestDelegate ( null , httpContext ) ;
104
- } ;
105
- }
106
-
107
88
/// <summary>
108
89
/// Creates a <see cref="RequestDelegate"/> implementation for <paramref name="methodInfo"/>.
109
90
/// </summary>
110
91
/// <param name="methodInfo">A request handler with any number of custom parameters that often produces a response with its return value.</param>
111
- /// <param name="serviceProvider">The <see cref="IServiceProvider"/> instance used to detect which parameters are services.</param>
112
92
/// <param name="targetFactory">Creates the <see langword="this"/> for the non-static method.</param>
93
+ /// <param name="options">The <see cref="RequestDelegateFactoryOptions"/> used to configure the behavior of the handler.</param>
113
94
/// <returns>The <see cref="RequestDelegate"/>.</returns>
114
- public static RequestDelegate Create ( MethodInfo methodInfo , IServiceProvider ? serviceProvider , Func < HttpContext , object > targetFactory )
95
+ #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters
96
+ public static RequestDelegate Create ( MethodInfo methodInfo , Func < HttpContext , object > ? targetFactory = null , RequestDelegateFactoryOptions ? options = null )
97
+ #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters
115
98
{
116
99
if ( methodInfo is null )
117
100
{
118
101
throw new ArgumentNullException ( nameof ( methodInfo ) ) ;
119
102
}
120
103
121
- if ( targetFactory is null )
104
+ if ( methodInfo . DeclaringType is null )
122
105
{
123
- throw new ArgumentNullException ( nameof ( targetFactory ) ) ;
106
+ throw new ArgumentException ( $ " { nameof ( methodInfo ) } does not have a declaring type." ) ;
124
107
}
125
108
126
- if ( methodInfo . DeclaringType is null )
109
+ if ( targetFactory is null )
127
110
{
128
- throw new ArgumentException ( $ "A { nameof ( targetFactory ) } was provided, but { nameof ( methodInfo ) } does not have a Declaring type.") ;
111
+ if ( methodInfo . IsStatic )
112
+ {
113
+ var untargetableRequestDelegate = CreateTargetableRequestDelegate ( methodInfo , options , targetExpression : null ) ;
114
+
115
+ return httpContext =>
116
+ {
117
+ return untargetableRequestDelegate ( null , httpContext ) ;
118
+ } ;
119
+ }
120
+
121
+ targetFactory = context => Activator . CreateInstance ( methodInfo . DeclaringType ) ! ;
129
122
}
130
123
131
124
var targetExpression = Expression . Convert ( TargetExpr , methodInfo . DeclaringType ) ;
132
- var targetableRequestDelegate = CreateTargetableRequestDelegate ( methodInfo , serviceProvider , targetExpression ) ;
125
+ var targetableRequestDelegate = CreateTargetableRequestDelegate ( methodInfo , options , targetExpression ) ;
133
126
134
127
return httpContext =>
135
128
{
136
129
return targetableRequestDelegate ( targetFactory ( httpContext ) , httpContext ) ;
137
130
} ;
138
131
}
139
132
140
- private static Func < object ? , HttpContext , Task > CreateTargetableRequestDelegate ( MethodInfo methodInfo , IServiceProvider ? serviceProvider , Expression ? targetExpression )
133
+ private static Func < object ? , HttpContext , Task > CreateTargetableRequestDelegate ( MethodInfo methodInfo , RequestDelegateFactoryOptions ? options , Expression ? targetExpression )
141
134
{
142
135
// Non void return type
143
136
@@ -157,9 +150,14 @@ public static RequestDelegate Create(MethodInfo methodInfo, IServiceProvider? se
157
150
158
151
var factoryContext = new FactoryContext ( )
159
152
{
160
- ServiceProviderIsService = serviceProvider ? . GetService < IServiceProviderIsService > ( )
153
+ ServiceProviderIsService = options ? . ServiceProvider ? . GetService < IServiceProviderIsService > ( )
161
154
} ;
162
155
156
+ if ( options ? . RouteParameterNames is { } routeParameterNames )
157
+ {
158
+ factoryContext . RouteParameters = new ( routeParameterNames ) ;
159
+ }
160
+
163
161
var arguments = CreateArguments ( methodInfo . GetParameters ( ) , factoryContext ) ;
164
162
165
163
var responseWritingMethodCall = factoryContext . TryParseParams . Count > 0 ?
@@ -202,6 +200,11 @@ private static Expression CreateArgument(ParameterInfo parameter, FactoryContext
202
200
203
201
if ( parameterCustomAttributes . OfType < IFromRouteMetadata > ( ) . FirstOrDefault ( ) is { } routeAttribute )
204
202
{
203
+ if ( factoryContext . RouteParameters is { } routeParams && ! routeParams . Contains ( parameter . Name ) )
204
+ {
205
+ throw new InvalidOperationException ( $ "{ parameter . Name } is not a route paramter.") ;
206
+ }
207
+
205
208
return BindParameterFromProperty ( parameter , RouteValuesExpr , routeAttribute . Name ?? parameter . Name , factoryContext ) ;
206
209
}
207
210
else if ( parameterCustomAttributes . OfType < IFromQueryMetadata > ( ) . FirstOrDefault ( ) is { } queryAttribute )
@@ -242,6 +245,13 @@ private static Expression CreateArgument(ParameterInfo parameter, FactoryContext
242
245
}
243
246
else if ( parameter . ParameterType == typeof ( string ) || TryParseMethodCache . HasTryParseMethod ( parameter ) )
244
247
{
248
+ // We're in the fallback case and we have a parameter and route parameter match so don't fallback
249
+ // to query string in this case
250
+ if ( factoryContext . RouteParameters is { } routeParams && routeParams . Contains ( parameter . Name ) )
251
+ {
252
+ return BindParameterFromProperty ( parameter , RouteValuesExpr , parameter . Name , factoryContext ) ;
253
+ }
254
+
245
255
return BindParameterFromRouteValueOrQueryString ( parameter , parameter . Name , factoryContext ) ;
246
256
}
247
257
else
@@ -814,6 +824,7 @@ private class FactoryContext
814
824
public Type ? JsonRequestBodyType { get ; set ; }
815
825
public bool AllowEmptyRequestBody { get ; set ; }
816
826
public IServiceProviderIsService ? ServiceProviderIsService { get ; init ; }
827
+ public List < string > ? RouteParameters { get ; set ; }
817
828
818
829
public bool UsingTempSourceString { get ; set ; }
819
830
public List < ( ParameterExpression , Expression ) > TryParseParams { get ; } = new ( ) ;
0 commit comments