@@ -7,6 +7,7 @@ namespace Asp.Versioning.ApiExplorer;
7
7
using Microsoft . AspNetCore . Mvc . ApiExplorer ;
8
8
using Microsoft . AspNetCore . Mvc . ModelBinding ;
9
9
using Microsoft . AspNetCore . Routing ;
10
+ using Microsoft . AspNetCore . Routing . Patterns ;
10
11
using static Asp . Versioning . ApiVersionParameterLocation ;
11
12
using static System . Linq . Enumerable ;
12
13
using static System . StringComparison ;
@@ -36,9 +37,9 @@ public ApiVersionParameterDescriptionContext(
36
37
ApiExplorerOptions options )
37
38
{
38
39
Options = options ?? throw new ArgumentNullException ( nameof ( options ) ) ;
39
- ApiDescription = apiDescription ;
40
- ApiVersion = apiVersion ;
41
- ModelMetadata = modelMetadata ;
40
+ ApiDescription = apiDescription ?? throw new ArgumentNullException ( nameof ( apiDescription ) ) ;
41
+ ApiVersion = apiVersion ?? throw new ArgumentNullException ( nameof ( apiVersion ) ) ;
42
+ ModelMetadata = modelMetadata ?? throw new ArgumentNullException ( nameof ( modelMetadata ) ) ;
42
43
optional = options . AssumeDefaultVersionWhenUnspecified && apiVersion == options . DefaultApiVersion ;
43
44
}
44
45
@@ -158,13 +159,8 @@ protected virtual void AddHeader( string name )
158
159
/// </summary>
159
160
protected virtual void UpdateUrlSegment ( )
160
161
{
161
- var query = from description in ApiDescription . ParameterDescriptions
162
- let routeInfo = description . RouteInfo
163
- where routeInfo != null
164
- let constraints = routeInfo . Constraints ?? Empty < IRouteConstraint > ( )
165
- where constraints . OfType < ApiVersionRouteConstraint > ( ) . Any ( )
166
- select description ;
167
- var parameter = query . FirstOrDefault ( ) ;
162
+ var parameter = FindByRouteConstraintType ( ApiDescription ) ??
163
+ FindByRouteConstraintName ( ApiDescription , Options . RouteConstraintName ) ;
168
164
169
165
if ( parameter == null )
170
166
{
@@ -184,7 +180,7 @@ where constraints.OfType<ApiVersionRouteConstraint>().Any()
184
180
185
181
if ( parameter . ParameterDescriptor == null )
186
182
{
187
- parameter . ParameterDescriptor = new ParameterDescriptor ( )
183
+ parameter . ParameterDescriptor = new ( )
188
184
{
189
185
Name = parameter . Name ,
190
186
ParameterType = typeof ( ApiVersion ) ,
@@ -245,6 +241,74 @@ protected virtual void AddMediaTypeParameter( string name )
245
241
}
246
242
}
247
243
244
+ private static ApiParameterDescription ? FindByRouteConstraintType ( ApiDescription description )
245
+ {
246
+ var parameters = description . ParameterDescriptions ;
247
+
248
+ for ( var i = 0 ; i < parameters . Count ; i ++ )
249
+ {
250
+ var parameter = parameters [ i ] ;
251
+
252
+ if ( parameter . RouteInfo is ApiParameterRouteInfo routeInfo &&
253
+ routeInfo . Constraints is IEnumerable < IRouteConstraint > constraints &&
254
+ constraints . OfType < ApiVersionRouteConstraint > ( ) . Any ( ) )
255
+ {
256
+ return parameter ;
257
+ }
258
+ }
259
+
260
+ return default ;
261
+ }
262
+
263
+ private static ApiParameterDescription ? FindByRouteConstraintName ( ApiDescription description , string constraintName )
264
+ {
265
+ var relativePath = description . RelativePath ;
266
+
267
+ if ( string . IsNullOrEmpty ( relativePath ) )
268
+ {
269
+ return default ;
270
+ }
271
+
272
+ var routePattern = RoutePatternFactory . Parse ( relativePath ) ;
273
+ var parameters = routePattern . Parameters ;
274
+ var parameterDescriptions = description . ParameterDescriptions ;
275
+
276
+ for ( var i = 0 ; i < parameters . Count ; i ++ )
277
+ {
278
+ var parameter = parameters [ i ] ;
279
+ var policies = parameter . ParameterPolicies ;
280
+
281
+ for ( var j = 0 ; j < policies . Count ; j ++ )
282
+ {
283
+ if ( ! constraintName . Equals ( policies [ j ] . Content , Ordinal ) )
284
+ {
285
+ continue ;
286
+ }
287
+
288
+ for ( var k = 0 ; k < parameterDescriptions . Count ; k ++ )
289
+ {
290
+ var parameterDescription = parameterDescriptions [ k ] ;
291
+
292
+ if ( parameterDescription . Name != parameter . Name &&
293
+ parameterDescription . ParameterDescriptor ? . ParameterType != typeof ( ApiVersion ) )
294
+ {
295
+ continue ;
296
+ }
297
+
298
+ var token = $ "{ parameter . Name } :{ constraintName } ";
299
+
300
+ parameterDescription . Name = parameter . Name ;
301
+ description . RelativePath = relativePath . Replace ( token , parameter . Name , Ordinal ) ;
302
+ parameterDescription . Source = BindingSource . Path ;
303
+
304
+ return parameterDescription ;
305
+ }
306
+ }
307
+ }
308
+
309
+ return default ;
310
+ }
311
+
248
312
private ApiParameterDescription NewApiVersionParameter ( string name , BindingSource source )
249
313
{
250
314
var parameter = new ApiParameterDescription ( )
0 commit comments