@@ -142,6 +142,13 @@ public virtual ActionDescriptor SelectBestCandidate( RouteContext context, IRead
142
142
}
143
143
144
144
var matches = EvaluateActionConstraints ( context , candidates ) ;
145
+ var selectedAction = SelectActionWithoutApiVersionConvention ( matches ) ;
146
+
147
+ if ( selectedAction != null )
148
+ {
149
+ return selectedAction ;
150
+ }
151
+
145
152
var selectionContext = new ActionSelectionContext ( httpContext , matches , apiVersion ) ;
146
153
var finalMatches = SelectBestActions ( selectionContext ) ;
147
154
var properties = httpContext . ApiVersionProperties ( ) ;
@@ -150,34 +157,18 @@ public virtual ActionDescriptor SelectBestCandidate( RouteContext context, IRead
150
157
properties . ApiVersion = selectionContext . RequestedVersion ;
151
158
selectionResult . AddCandidates ( candidates ) ;
152
159
153
- if ( finalMatches = = null )
160
+ if ( finalMatches ! = null )
154
161
{
155
- selectionResult . EndIteration ( ) ;
156
- return null ;
157
- }
158
-
159
- if ( finalMatches . Count == 1 )
160
- {
161
- var selectedAction = finalMatches [ 0 ] ;
162
-
163
- // note: short-circuit if the api version policy has already been applied to the match
164
- // and there are no other matches in a previous iteration which would take precendence
165
- if ( selectedAction . VersionPolicyIsApplied ( ) && ! selectionResult . HasMatchesInPreviousIterations )
162
+ if ( ( selectedAction = SelectActionWithApiVersionPolicyApplied ( finalMatches , selectionResult ) ) == null )
163
+ {
164
+ AppendPossibleMatches ( finalMatches , context , selectionResult ) ;
165
+ }
166
+ else
166
167
{
167
- httpContext . ApiVersionProperties ( ) . ApiVersion = selectionContext . RequestedVersion ;
168
168
return selectedAction ;
169
169
}
170
170
}
171
171
172
- if ( finalMatches . Count > 0 )
173
- {
174
- var routeData = new RouteData ( context . RouteData ) ;
175
- var matchingActions = new MatchingActionSequence ( finalMatches , routeData ) ;
176
-
177
- selectionResult . AddMatches ( matchingActions ) ;
178
- selectionResult . TrySetBestMatch ( matchingActions . BestMatch ) ;
179
- }
180
-
181
172
// note: even though we may have had a successful match, this method could be called multiple times. the final decision
182
173
// is made by the IApiVersionRoutePolicy. we return here to make sure all candidates have been considered at least once.
183
174
selectionResult . EndIteration ( ) ;
@@ -238,6 +229,63 @@ where ActionIsSatisfiedBy( action, model, context.RequestedVersion, implicitMatc
238
229
return bestMatches ;
239
230
}
240
231
232
+ ActionDescriptor SelectActionWithoutApiVersionConvention ( IReadOnlyList < ActionDescriptor > matches )
233
+ {
234
+ Contract . Requires ( matches != null ) ;
235
+
236
+ if ( matches . Count != 1 )
237
+ {
238
+ return null ;
239
+ }
240
+
241
+ var selectedAction = matches [ 0 ] ;
242
+
243
+ if ( selectedAction . GetProperty < ApiVersionModel > ( ) == null )
244
+ {
245
+ return selectedAction ;
246
+ }
247
+
248
+ return null ;
249
+ }
250
+
251
+ ActionDescriptor SelectActionWithApiVersionPolicyApplied ( IReadOnlyList < ActionDescriptor > matches , ActionSelectionResult result )
252
+ {
253
+ Contract . Requires ( matches != null ) ;
254
+ Contract . Requires ( result != null ) ;
255
+
256
+ if ( matches . Count != 1 )
257
+ {
258
+ return null ;
259
+ }
260
+
261
+ var match = matches [ 0 ] ;
262
+
263
+ if ( match . VersionPolicyIsApplied ( ) && ! result . HasMatchesInPreviousIterations )
264
+ {
265
+ return match ;
266
+ }
267
+
268
+ return null ;
269
+ }
270
+
271
+ void AppendPossibleMatches ( IReadOnlyList < ActionDescriptor > matches , RouteContext context , ActionSelectionResult result )
272
+ {
273
+ Contract . Requires ( matches != null ) ;
274
+ Contract . Requires ( context != null ) ;
275
+ Contract . Requires ( result != null ) ;
276
+
277
+ if ( matches . Count == 0 )
278
+ {
279
+ return ;
280
+ }
281
+
282
+ var routeData = new RouteData ( context . RouteData ) ;
283
+ var matchingActions = new MatchingActionSequence ( matches , routeData ) ;
284
+
285
+ result . AddMatches ( matchingActions ) ;
286
+ result . TrySetBestMatch ( matchingActions . BestMatch ) ;
287
+ }
288
+
241
289
RequestHandler VerifyRequestedApiVersionIsNotAmbiguous ( HttpContext httpContext , out ApiVersion apiVersion )
242
290
{
243
291
Contract . Requires ( httpContext != null ) ;
@@ -474,8 +522,8 @@ public Cache( ActionDescriptorCollection actions )
474
522
Contract . Requires ( actions != null ) ;
475
523
476
524
Version = actions . Version ;
477
- OrdinalEntries = new Dictionary < string [ ] , List < ActionDescriptor > > ( StringArrayComparer . Ordinal ) ;
478
- OrdinalIgnoreCaseEntries = new Dictionary < string [ ] , List < ActionDescriptor > > ( StringArrayComparer . OrdinalIgnoreCase ) ;
525
+ OrdinalEntries = new Dictionary < string [ ] , List < ActionDescriptor > > ( StringArrayComparer . Ordinal ) ;
526
+ OrdinalIgnoreCaseEntries = new Dictionary < string [ ] , List < ActionDescriptor > > ( StringArrayComparer . OrdinalIgnoreCase ) ;
479
527
RouteKeys = IdentifyRouteKeysForActionSelection ( actions ) ;
480
528
BuildOrderedSetOfKeysForRouteValues ( actions ) ;
481
529
}
@@ -500,7 +548,7 @@ static string[] IdentifyRouteKeysForActionSelection( ActionDescriptorCollection
500
548
{
501
549
foreach ( var kvp in action . RouteValues )
502
550
{
503
- routeKeys . Add ( kvp . Key ) ;
551
+ routeKeys . Add ( kvp . Key ) ;
504
552
}
505
553
}
506
554
}
@@ -526,7 +574,7 @@ void BuildOrderedSetOfKeysForRouteValues( ActionDescriptorCollection actions )
526
574
for ( var j = 0 ; j < RouteKeys . Length ; j ++ )
527
575
{
528
576
529
- action . RouteValues . TryGetValue ( RouteKeys [ j ] , out routeValues [ j ] ) ;
577
+ action . RouteValues . TryGetValue ( RouteKeys [ j ] , out routeValues [ j ] ) ;
530
578
}
531
579
532
580
if ( ! OrdinalIgnoreCaseEntries . TryGetValue ( routeValues , out var entries ) )
@@ -535,7 +583,7 @@ void BuildOrderedSetOfKeysForRouteValues( ActionDescriptorCollection actions )
535
583
OrdinalIgnoreCaseEntries . Add ( routeValues , entries ) ;
536
584
}
537
585
538
- entries . Add ( action ) ;
586
+ entries . Add ( action ) ;
539
587
540
588
if ( ! OrdinalEntries . ContainsKey ( routeValues ) )
541
589
{
0 commit comments