13
13
using System . Web . Http . Controllers ;
14
14
using System . Web . Http . Routing ;
15
15
using System . Web . Http . Services ;
16
+ using static Microsoft . Web . Http . Versioning . ApiVersionMapping ;
16
17
using static System . Net . HttpStatusCode ;
17
18
using static System . StringComparer ;
18
19
@@ -34,30 +35,27 @@ sealed class ActionSelectorCacheItem
34
35
readonly CandidateAction [ ] combinedCandidateActions ;
35
36
readonly IDictionary < HttpActionDescriptor , string [ ] > actionParameterNames = new Dictionary < HttpActionDescriptor , string [ ] > ( ) ;
36
37
readonly ILookup < string , HttpActionDescriptor > combinedActionNameMapping ;
37
- readonly HashSet < HttpMethod > allowedMethods = new HashSet < HttpMethod > ( ) ;
38
38
StandardActionSelectionCache ? standardActions ;
39
39
40
40
internal ActionSelectorCacheItem ( HttpControllerDescriptor controllerDescriptor )
41
41
{
42
42
this . controllerDescriptor = controllerDescriptor ;
43
43
44
- var allMethods = this . controllerDescriptor . ControllerType . GetMethods ( BindingFlags . Instance | BindingFlags . Public ) ;
45
- var validMethods = Array . FindAll ( allMethods , IsValidActionMethod ) ;
44
+ var validMethods = this . controllerDescriptor . ControllerType
45
+ . GetMethods ( BindingFlags . Instance | BindingFlags . Public )
46
+ . Where ( IsValidActionMethod )
47
+ . ToArray ( ) ;
46
48
47
49
combinedCandidateActions = new CandidateAction [ validMethods . Length ] ;
48
50
49
51
for ( var i = 0 ; i < validMethods . Length ; i ++ )
50
52
{
51
- var method = validMethods [ i ] ;
52
- var actionDescriptor = new ReflectedHttpActionDescriptor ( controllerDescriptor , method ) ;
53
- var actionBinding = actionDescriptor . ActionBinding ;
53
+ var actionDescriptor = new ReflectedHttpActionDescriptor ( controllerDescriptor , validMethods [ i ] ) ;
54
54
55
- allowedMethods . AddRange ( actionDescriptor . SupportedHttpMethods ) ;
56
55
combinedCandidateActions [ i ] = new CandidateAction ( actionDescriptor ) ;
57
-
58
56
actionParameterNames . Add (
59
57
actionDescriptor ,
60
- actionBinding . ParameterBindings
58
+ actionDescriptor . ActionBinding . ParameterBindings
61
59
. Where ( binding => ! binding . Descriptor . IsOptional && binding . Descriptor . ParameterType . CanConvertFromString ( ) && binding . WillReadUri ( ) )
62
60
. Select ( binding => binding . Descriptor . Prefix ?? binding . Descriptor . ParameterName ) . ToArray ( ) ) ;
63
61
}
@@ -193,6 +191,27 @@ IReadOnlyList<CandidateHttpActionDescriptor> FindMatchingActions( HttpController
193
191
return selectedCandidates . Select ( c => new CandidateHttpActionDescriptor ( c ) ) . ToArray ( ) ;
194
192
}
195
193
194
+ IEnumerable < HttpMethod > GetAllowedMethods ( HttpControllerContext controllerContext )
195
+ {
196
+ var request = controllerContext . Request ;
197
+ var apiModel = controllerContext . ControllerDescriptor . GetApiVersionModel ( ) ;
198
+ var version = apiModel . IsApiVersionNeutral ? ApiVersion . Neutral : request . ApiVersionProperties ( ) . RequestedApiVersion ! ;
199
+ var httpMethods = new HashSet < HttpMethod > ( ) ;
200
+
201
+ for ( var i = 0 ; i < combinedCandidateActions . Length ; i ++ )
202
+ {
203
+ var actionDescriptor = combinedCandidateActions [ i ] . ActionDescriptor ;
204
+ var endpointModel = actionDescriptor . GetApiVersionModel ( Explicit ) ;
205
+
206
+ if ( endpointModel . IsApiVersionNeutral || endpointModel . ImplementedApiVersions . Contains ( version ) )
207
+ {
208
+ httpMethods . AddRange ( actionDescriptor . SupportedHttpMethods ) ;
209
+ }
210
+ }
211
+
212
+ return httpMethods ;
213
+ }
214
+
196
215
HttpResponseMessage CreateSelectionError ( HttpControllerContext controllerContext )
197
216
{
198
217
var actionsFoundByParams = FindMatchingActions ( controllerContext , ignoreVerbs : true ) ;
@@ -204,9 +223,10 @@ HttpResponseMessage CreateSelectionError( HttpControllerContext controllerContex
204
223
205
224
var request = controllerContext . Request ;
206
225
var model = controllerContext . ControllerDescriptor . GetApiVersionModel ( ) ;
226
+ var httpMethods = GetAllowedMethods ( controllerContext ) ;
207
227
var exceptionFactory = new HttpResponseExceptionFactory ( request , new Lazy < ApiVersionModel > ( ( ) => model ) ) ;
208
228
209
- return exceptionFactory . CreateMethodNotAllowedResponse ( model . IsApiVersionNeutral , allowedMethods ) ;
229
+ return exceptionFactory . CreateMethodNotAllowedResponse ( model . IsApiVersionNeutral , httpMethods ) ;
210
230
}
211
231
212
232
HttpResponseMessage CreateActionNotFoundResponse ( HttpControllerContext controllerContext )
@@ -276,9 +296,10 @@ CandidateAction[] GetInitialCandidateList( HttpControllerContext controllerConte
276
296
{
277
297
var request = controllerContext . Request ;
278
298
var model = controllerContext . ControllerDescriptor . GetApiVersionModel ( ) ;
299
+ var httpMethods = GetAllowedMethods ( controllerContext ) ;
279
300
var exceptionFactory = new HttpResponseExceptionFactory ( request , new Lazy < ApiVersionModel > ( ( ) => model ) ) ;
280
301
281
- throw exceptionFactory . NewMethodNotAllowedException ( model . IsApiVersionNeutral , allowedMethods ) ;
302
+ throw exceptionFactory . NewMethodNotAllowedException ( model . IsApiVersionNeutral , httpMethods ) ;
282
303
}
283
304
284
305
var candidatesFoundByName = new CandidateAction [ actionsFoundByName . Length ] ;
0 commit comments