|
6 | 6 | using System.Diagnostics.CodeAnalysis;
|
7 | 7 | using System.Diagnostics.Contracts;
|
8 | 8 | using System.Linq;
|
9 |
| - using System.Net; |
10 | 9 | using System.Net.Http;
|
11 | 10 | using System.Reflection;
|
12 | 11 | using System.Text;
|
@@ -124,41 +123,72 @@ internal HttpActionDescriptor SelectAction( HttpControllerContext controllerCont
|
124 | 123 |
|
125 | 124 | InitializeStandardActions();
|
126 | 125 |
|
127 |
| - var selectedCandidates = FindMatchingActions( controllerContext ); |
| 126 | + var firstAttempt = FindAction( controllerContext, selector, ignoreSubRoutes: false ); |
| 127 | + |
| 128 | + if ( firstAttempt.Succeeded ) |
| 129 | + { |
| 130 | + return firstAttempt.Action; |
| 131 | + } |
| 132 | + |
| 133 | + if ( controllerContext.RouteData.GetSubRoutes() == null ) |
| 134 | + { |
| 135 | + throw firstAttempt.Exception; |
| 136 | + } |
| 137 | + |
| 138 | + var secondAttempt = FindAction( controllerContext, selector, ignoreSubRoutes: true ); |
| 139 | + |
| 140 | + if ( secondAttempt.Succeeded ) |
| 141 | + { |
| 142 | + return secondAttempt.Action; |
| 143 | + } |
| 144 | + |
| 145 | + throw firstAttempt.Exception; |
| 146 | + } |
| 147 | + |
| 148 | + private ActionSelectionResult FindAction( HttpControllerContext controllerContext, Func<HttpControllerContext, IReadOnlyList<HttpActionDescriptor>, HttpActionDescriptor> selector, bool ignoreSubRoutes ) |
| 149 | + { |
| 150 | + Contract.Requires( controllerContext != null ); |
| 151 | + Contract.Requires( selector != null ); |
| 152 | + Contract.Ensures( Contract.Result<ActionSelectionResult>() != null ); |
| 153 | + |
| 154 | + var selectedCandidates = FindMatchingActions( controllerContext, ignoreSubRoutes ); |
128 | 155 |
|
129 | 156 | if ( selectedCandidates.Count == 0 )
|
130 | 157 | {
|
131 |
| - throw new HttpResponseException( CreateSelectionError( controllerContext ) ); |
| 158 | + return new ActionSelectionResult( new HttpResponseException( CreateSelectionError( controllerContext ) ) ); |
132 | 159 | }
|
133 | 160 |
|
134 | 161 | var action = selector( controllerContext, selectedCandidates ) as CandidateHttpActionDescriptor;
|
135 | 162 |
|
136 | 163 | if ( action != null )
|
137 | 164 | {
|
138 | 165 | ElevateRouteData( controllerContext, action.CandidateAction );
|
139 |
| - return action; |
| 166 | + return new ActionSelectionResult( action ); |
140 | 167 | }
|
141 | 168 |
|
142 | 169 | if ( selectedCandidates.Count == 1 )
|
143 | 170 | {
|
144 |
| - throw new HttpResponseException( CreateSelectionError( controllerContext ) ); |
| 171 | + return new ActionSelectionResult( new HttpResponseException( CreateSelectionError( controllerContext ) ) ); |
145 | 172 | }
|
146 | 173 |
|
147 | 174 | var ambiguityList = CreateAmbiguousMatchList( selectedCandidates );
|
148 |
| - throw new InvalidOperationException( SR.ApiControllerActionSelector_AmbiguousMatch.FormatDefault( ambiguityList ) ); |
| 175 | + |
| 176 | + return new ActionSelectionResult( new InvalidOperationException( SR.ApiControllerActionSelector_AmbiguousMatch.FormatDefault( ambiguityList ) ) ); |
149 | 177 | }
|
150 | 178 |
|
151 | 179 | private static void ElevateRouteData( HttpControllerContext controllerContext, CandidateActionWithParams selectedCandidate ) => controllerContext.RouteData = selectedCandidate.RouteDataSource;
|
152 | 180 |
|
153 |
| - private IReadOnlyList<CandidateHttpActionDescriptor> FindMatchingActions( HttpControllerContext controllerContext, bool ignoreVerbs = false ) |
| 181 | + private IReadOnlyList<CandidateHttpActionDescriptor> FindMatchingActions( HttpControllerContext controllerContext, bool ignoreSubRoutes = false, bool ignoreVerbs = false ) |
154 | 182 | {
|
155 | 183 | Contract.Requires( controllerContext != null );
|
156 | 184 | Contract.Ensures( Contract.Result<IReadOnlyList<CandidateHttpActionDescriptor>>() != null );
|
157 | 185 |
|
158 | 186 | var routeData = controllerContext.RouteData;
|
159 |
| - var subRoutes = routeData.GetSubRoutes(); |
160 |
| - var actionsWithParameters = GetInitialCandidateWithParameterListForRegularRoutes( controllerContext, ignoreVerbs ) |
161 |
| - .Union( GetInitialCandidateWithParameterListForDirectRoutes( controllerContext, subRoutes, ignoreVerbs ) ); |
| 187 | + var subRoutes = ignoreSubRoutes ? default( IEnumerable<IHttpRouteData> ) : routeData.GetSubRoutes(); |
| 188 | + var actionsWithParameters = subRoutes == null ? |
| 189 | + GetInitialCandidateWithParameterListForRegularRoutes( controllerContext, ignoreVerbs ) : |
| 190 | + GetInitialCandidateWithParameterListForDirectRoutes( controllerContext, subRoutes, ignoreVerbs ); |
| 191 | + |
162 | 192 | var actionsFoundByParams = FindActionMatchRequiredRouteAndQueryParameters( actionsWithParameters );
|
163 | 193 | var orderCandidates = RunOrderFilter( actionsFoundByParams );
|
164 | 194 | var precedenceCandidates = RunPrecedenceFilter( orderCandidates );
|
|
0 commit comments