@@ -324,69 +324,91 @@ protected virtual bool TryExpandUriParameters( IHttpRoute route, IParsedRoute pa
324
324
325
325
foreach ( var parameterDescription in parameterDescriptions )
326
326
{
327
- if ( parameterDescription . Source == FromUri )
327
+ switch ( parameterDescription . Source )
328
328
{
329
- if ( parameterDescription . ParameterDescriptor == null )
330
- {
331
- // Undeclared route parameter handling generates query string like "?name={name}"
332
- AddPlaceholder ( parameterValuesForRoute , parameterDescription . Name ) ;
333
- }
334
- else if ( parameterDescription . ParameterDescriptor . ParameterType . CanConvertFromString ( ) )
335
- {
336
- // Simple type generates query string like "?name={name}"
337
- AddPlaceholder ( parameterValuesForRoute , parameterDescription . Name ) ;
338
- }
339
- else if ( IsBindableCollection ( parameterDescription . ParameterDescriptor . ParameterType ) )
340
- {
341
- var parameterName = parameterDescription . ParameterDescriptor . ParameterName ;
342
- var innerType = GetCollectionElementType ( parameterDescription . ParameterDescriptor . ParameterType ) ;
343
- var innerTypeProperties = innerType . GetBindableProperties ( ) . ToArray ( ) ;
329
+ case FromUri :
330
+ if ( parameterDescription . ParameterDescriptor == null )
331
+ {
332
+ // Undeclared route parameter handling generates query string like "?name={name}"
333
+ AddPlaceholder ( parameterValuesForRoute , parameterDescription . Name ) ;
334
+ continue ;
335
+ }
336
+
337
+ var parameterType = parameterDescription . ParameterDescriptor . ParameterType ;
344
338
345
- if ( innerTypeProperties . Any ( ) )
339
+ if ( IsApiVersionRouteParameter ( parameterType , route . Constraints . Values ) )
346
340
{
347
- // Complex array and collection generate query string like
348
- // "?name[0].foo={name[0].foo}&name[0].bar={name[0].bar}&name[1].foo={name[1].foo}&name[1].bar={name[1].bar}"
349
- AddPlaceholderForProperties ( parameterValuesForRoute , innerTypeProperties , parameterName + "[0]." ) ;
350
- AddPlaceholderForProperties ( parameterValuesForRoute , innerTypeProperties , parameterName + "[1]." ) ;
341
+ // model build parameter based on route constraint like "api/v{version:apiVersion}"
342
+ AddPlaceholder ( parameterValuesForRoute , parameterDescription . Name ) ;
351
343
}
352
- else
344
+ else if ( parameterType . CanConvertFromString ( ) )
353
345
{
354
- // Simple array and collection generate query string like "?name[0]={name[0]}&name[1]={name[1]}".
355
- AddPlaceholder ( parameterValuesForRoute , parameterName + "[0]" ) ;
356
- AddPlaceholder ( parameterValuesForRoute , parameterName + "[1]" ) ;
346
+ // Simple type generates query string like "?name={name}"
347
+ AddPlaceholder ( parameterValuesForRoute , parameterDescription . Name ) ;
357
348
}
358
- }
359
- else if ( IsBindableKeyValuePair ( parameterDescription . ParameterDescriptor . ParameterType ) )
360
- {
361
- // KeyValuePair generates query string like "?key={key}&value={value}"
362
- AddPlaceholder ( parameterValuesForRoute , "key" ) ;
363
- AddPlaceholder ( parameterValuesForRoute , "value" ) ;
364
- }
365
- else if ( IsBindableDictionry ( parameterDescription . ParameterDescriptor . ParameterType ) )
366
- {
367
- // Dictionary generates query string like
368
- // "?dict[0].key={dict[0].key}&dict[0].value={dict[0].value}&dict[1].key={dict[1].key}&dict[1].value={dict[1].value}"
369
- var parameterName = parameterDescription . ParameterDescriptor . ParameterName ;
370
- AddPlaceholder ( parameterValuesForRoute , parameterName + "[0].key" ) ;
371
- AddPlaceholder ( parameterValuesForRoute , parameterName + "[0].value" ) ;
372
- AddPlaceholder ( parameterValuesForRoute , parameterName + "[1].key" ) ;
373
- AddPlaceholder ( parameterValuesForRoute , parameterName + "[1].value" ) ;
374
- }
375
- else if ( parameterDescription . CanConvertPropertiesFromString ( ) )
376
- {
377
- if ( emitPrefixes )
349
+ else if ( IsBindableCollection ( parameterType ) )
378
350
{
379
- prefix = parameterDescription . Name + "." ;
351
+ var parameterName = parameterDescription . ParameterDescriptor . ParameterName ;
352
+ var innerType = GetCollectionElementType ( parameterType ) ;
353
+ var innerTypeProperties = innerType . GetBindableProperties ( ) . ToArray ( ) ;
354
+
355
+ if ( innerTypeProperties . Any ( ) )
356
+ {
357
+ // Complex array and collection generate query string like
358
+ // "?name[0].foo={name[0].foo}&name[0].bar={name[0].bar}&name[1].foo={name[1].foo}&name[1].bar={name[1].bar}"
359
+ AddPlaceholderForProperties ( parameterValuesForRoute , innerTypeProperties , parameterName + "[0]." ) ;
360
+ AddPlaceholderForProperties ( parameterValuesForRoute , innerTypeProperties , parameterName + "[1]." ) ;
361
+ }
362
+ else
363
+ {
364
+ // Simple array and collection generate query string like "?name[0]={name[0]}&name[1]={name[1]}".
365
+ AddPlaceholder ( parameterValuesForRoute , parameterName + "[0]" ) ;
366
+ AddPlaceholder ( parameterValuesForRoute , parameterName + "[1]" ) ;
367
+ }
368
+ }
369
+ else if ( IsBindableKeyValuePair ( parameterType ) )
370
+ {
371
+ // KeyValuePair generates query string like "?key={key}&value={value}"
372
+ AddPlaceholder ( parameterValuesForRoute , "key" ) ;
373
+ AddPlaceholder ( parameterValuesForRoute , "value" ) ;
374
+ }
375
+ else if ( IsBindableDictionry ( parameterType ) )
376
+ {
377
+ // Dictionary generates query string like
378
+ // "?dict[0].key={dict[0].key}&dict[0].value={dict[0].value}&dict[1].key={dict[1].key}&dict[1].value={dict[1].value}"
379
+ var parameterName = parameterDescription . ParameterDescriptor . ParameterName ;
380
+ AddPlaceholder ( parameterValuesForRoute , parameterName + "[0].key" ) ;
381
+ AddPlaceholder ( parameterValuesForRoute , parameterName + "[0].value" ) ;
382
+ AddPlaceholder ( parameterValuesForRoute , parameterName + "[1].key" ) ;
383
+ AddPlaceholder ( parameterValuesForRoute , parameterName + "[1].value" ) ;
380
384
}
385
+ else if ( parameterDescription . CanConvertPropertiesFromString ( ) )
386
+ {
387
+ if ( emitPrefixes )
388
+ {
389
+ prefix = parameterDescription . Name + "." ;
390
+ }
381
391
382
- // Inserting the individual properties of the object in the query string as all the complex object can not be converted from string,
383
- // but all its individual properties can.
384
- AddPlaceholderForProperties ( parameterValuesForRoute , parameterDescription . GetBindableProperties ( ) , prefix ) ;
385
- }
392
+ // Inserting the individual properties of the object in the query string as all the complex object can not be converted from string,
393
+ // but all its individual properties can.
394
+ AddPlaceholderForProperties ( parameterValuesForRoute , parameterDescription . GetBindableProperties ( ) , prefix ) ;
395
+ }
396
+
397
+ break ;
398
+ case Unknown :
399
+ if ( IsApiVersionRouteParameter ( parameterDescription , route . Constraints . Values ) )
400
+ {
401
+ // model build parameter based on route constraint like "api/v{version:apiVersion}"
402
+ AddPlaceholder ( parameterValuesForRoute , parameterDescription . Name ) ;
403
+ }
404
+
405
+ break ;
386
406
}
387
407
}
388
408
389
- var boundRouteTemplate = parsedRoute . Bind ( null , parameterValuesForRoute , new HttpRouteValueDictionary ( route . Defaults ) , new HttpRouteValueDictionary ( route . Constraints ) ) ;
409
+ var defaultValues = new HttpRouteValueDictionary ( route . Defaults ) ;
410
+ var constraints = new HttpRouteValueDictionary ( route . Constraints ) ;
411
+ var boundRouteTemplate = parsedRoute . Bind ( null , parameterValuesForRoute , defaultValues , constraints ) ;
390
412
391
413
if ( boundRouteTemplate == null )
392
414
{
@@ -398,6 +420,12 @@ protected virtual bool TryExpandUriParameters( IHttpRoute route, IParsedRoute pa
398
420
return true ;
399
421
}
400
422
423
+ static bool IsApiVersionRouteParameter ( ApiParameterDescription parameter , IEnumerable < object > constraints ) =>
424
+ parameter . ParameterDescriptor != null && IsApiVersionRouteParameter ( parameter . ParameterDescriptor . ParameterType , constraints ) ;
425
+
426
+ static bool IsApiVersionRouteParameter ( Type ? parameterType , IEnumerable < object > constraints ) =>
427
+ parameterType != null && typeof ( ApiVersion ) . IsAssignableFrom ( parameterType ) && constraints . OfType < ApiVersionRouteConstraint > ( ) . Any ( ) ;
428
+
401
429
static IEnumerable < IHttpRoute > FlattenRoutes ( IEnumerable < IHttpRoute > routes )
402
430
{
403
431
foreach ( var route in routes )
0 commit comments