@@ -324,69 +324,91 @@ protected virtual bool TryExpandUriParameters( IHttpRoute route, IParsedRoute pa
324324
325325 foreach ( var parameterDescription in parameterDescriptions )
326326 {
327- if ( parameterDescription . Source == FromUri )
327+ switch ( parameterDescription . Source )
328328 {
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 ;
344338
345- if ( innerTypeProperties . Any ( ) )
339+ if ( IsApiVersionRouteParameter ( parameterType , route . Constraints . Values ) )
346340 {
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 ) ;
351343 }
352- else
344+ else if ( parameterType . CanConvertFromString ( ) )
353345 {
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 ) ;
357348 }
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 ) )
378350 {
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" ) ;
380384 }
385+ else if ( parameterDescription . CanConvertPropertiesFromString ( ) )
386+ {
387+ if ( emitPrefixes )
388+ {
389+ prefix = parameterDescription . Name + "." ;
390+ }
381391
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 ;
386406 }
387407 }
388408
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 ) ;
390412
391413 if ( boundRouteTemplate == null )
392414 {
@@ -398,6 +420,12 @@ protected virtual bool TryExpandUriParameters( IHttpRoute route, IParsedRoute pa
398420 return true ;
399421 }
400422
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+
401429 static IEnumerable < IHttpRoute > FlattenRoutes ( IEnumerable < IHttpRoute > routes )
402430 {
403431 foreach ( var route in routes )
0 commit comments