|
1 | 1 | namespace Microsoft.AspNet.OData.Routing
|
2 | 2 | {
|
| 3 | + using Microsoft.AspNet.OData.Extensions; |
3 | 4 | using Microsoft.AspNetCore.Http;
|
4 | 5 | using Microsoft.AspNetCore.Mvc;
|
5 | 6 | using Microsoft.AspNetCore.Mvc.Versioning;
|
6 | 7 | using Microsoft.AspNetCore.Routing;
|
7 |
| - using Microsoft.Extensions.DependencyInjection; |
8 |
| - using Microsoft.Extensions.Options; |
9 |
| - using Microsoft.OData; |
10 | 8 | using System;
|
11 | 9 | using System.Diagnostics.Contracts;
|
12 | 10 | using static Microsoft.AspNetCore.Routing.RouteDirection;
|
@@ -50,48 +48,50 @@ public override bool Match( HttpContext httpContext, IRouter route, string route
|
50 | 48 | Arg.NotNull( route, nameof( route ) );
|
51 | 49 | Arg.NotNull( values, nameof( values ) );
|
52 | 50 |
|
53 |
| - if ( routeDirection == UrlGeneration ) |
| 51 | + if ( routeDirection == UrlGeneration || !TryGetRequestedApiVersion( httpContext, out var requestedVersion ) ) |
54 | 52 | {
|
| 53 | + // note: if an error occurs reading the api version, still let the base constraint |
| 54 | + // match the request. the IActionSelector will produce 400 during action selection. |
55 | 55 | return base.Match( httpContext, route, routeKey, values, routeDirection );
|
56 | 56 | }
|
57 | 57 |
|
58 |
| - var request = httpContext.Request; |
59 |
| - var feature = httpContext.Features.Get<IApiVersioningFeature>(); |
| 58 | + var matched = false; |
60 | 59 |
|
61 |
| - if ( !TryGetRequestedApiVersion( httpContext, feature, out var requestedVersion ) ) |
| 60 | + try |
62 | 61 | {
|
63 |
| - // note: if an error occurs reading the api version, still let the base constraint |
64 |
| - // match the request. the IActionSelector will produce 400 during action selection. |
65 |
| - return base.Match( httpContext, route, routeKey, values, routeDirection ); |
| 62 | + matched = base.Match( httpContext, route, routeKey, values, routeDirection ); |
66 | 63 | }
|
67 |
| - |
68 |
| - if ( requestedVersion != null ) |
| 64 | + catch ( InvalidOperationException ) |
69 | 65 | {
|
70 |
| - return ApiVersion == requestedVersion && base.Match( httpContext, route, routeKey, values, routeDirection ); |
| 66 | + // note: the base implementation of Match will setup the container. if this happens more |
| 67 | + // than once, an exception is thrown. this most often occurs when policy allows implicitly |
| 68 | + // matching an api version and all routes must be visited to determine their candidacy. if |
| 69 | + // this happens, delete the container and retry. |
| 70 | + httpContext.Request.DeleteRequestContainer( true ); |
| 71 | + matched = base.Match( httpContext, route, routeKey, values, routeDirection ); |
71 | 72 | }
|
72 | 73 |
|
73 |
| - var options = httpContext.RequestServices.GetRequiredService<IOptions<ApiVersioningOptions>>().Value; |
74 |
| - |
75 |
| - if ( options.DefaultApiVersion != ApiVersion || !base.Match( httpContext, route, routeKey, values, routeDirection ) ) |
| 74 | + if ( !matched ) |
76 | 75 | {
|
77 | 76 | return false;
|
78 | 77 | }
|
79 | 78 |
|
80 |
| - if ( options.AssumeDefaultVersionWhenUnspecified || IsServiceDocumentOrMetadataRoute( values ) ) |
| 79 | + if ( requestedVersion == null ) |
81 | 80 | {
|
82 |
| - feature.RequestedApiVersion = ApiVersion; |
| 81 | + // we definitely matched the route, but not necessarily the api version so |
| 82 | + // track this route as a matching candidate |
| 83 | + httpContext.ODataVersioningFeature().MatchingRoutes[ApiVersion] = RouteName; |
| 84 | + return false; |
83 | 85 | }
|
84 | 86 |
|
85 |
| - return true; |
| 87 | + return ApiVersion == requestedVersion; |
86 | 88 | }
|
87 | 89 |
|
88 |
| - static bool IsServiceDocumentOrMetadataRoute( RouteValueDictionary values ) => |
89 |
| - values.TryGetValue( "odataPath", out var value ) && ( value == null || Equals( value, "$metadata" ) ); |
90 |
| - |
91 |
| - static bool TryGetRequestedApiVersion( HttpContext httpContext, IApiVersioningFeature feature, out ApiVersion apiVersion ) |
| 90 | + static bool TryGetRequestedApiVersion( HttpContext httpContext, out ApiVersion apiVersion ) |
92 | 91 | {
|
93 | 92 | Contract.Requires( httpContext != null );
|
94 |
| - Contract.Requires( feature != null ); |
| 93 | + |
| 94 | + var feature = httpContext.Features.Get<IApiVersioningFeature>(); |
95 | 95 |
|
96 | 96 | try
|
97 | 97 | {
|
|
0 commit comments