/// <summary>
        /// Selects the best action given the provided route context and list of candidate actions.
        /// </summary>
        /// <param name="context">The current <see cref="RouteContext">route context</see> to evaluate.</param>
        /// <param name="candidates">The <see cref="IReadOnlyList{T}">read-only list</see> of candidate <see cref="ActionDescriptor">actions</see> to select from.</param>
        /// <returns>The best candidate <see cref="ActionDescriptor">action</see> or <c>null</c> if no candidate matches.</returns>
        public virtual ActionDescriptor SelectBestCandidate(RouteContext context, IReadOnlyList <ActionDescriptor> candidates)
        {
            Arg.NotNull(context, nameof(context));
            Arg.NotNull(candidates, nameof(candidates));

            var httpContext = context.HttpContext;

            if ((context.Handler = VerifyRequestedApiVersionIsNotAmbiguous(httpContext, out var apiVersion)) != null)
            {
                return(null);
            }

            var matches          = EvaluateActionConstraints(context, candidates);
            var selectionContext = new ActionSelectionContext(httpContext, matches, apiVersion);
            var finalMatches     = SelectBestActions(selectionContext);
            var properties       = httpContext.ApiVersionProperties();
            var selectionResult  = properties.SelectionResult;

            properties.ApiVersion = selectionContext.RequestedVersion;
            selectionResult.AddCandidates(candidates);

            if (finalMatches == null)
            {
                selectionResult.EndIteration();
                return(null);
            }

            if (finalMatches.Count == 1)
            {
                var selectedAction = finalMatches[0];

                // note: short-circuit if the api version policy has already been applied to the match
                // and there are no other matches in a previous iteration which would take precendence
                if (selectedAction.VersionPolicyIsApplied() && !selectionResult.HasMatchesInPreviousIterations)
                {
                    httpContext.ApiVersionProperties().ApiVersion = selectionContext.RequestedVersion;
                    return(selectedAction);
                }
            }

            if (finalMatches.Count > 0)
            {
                var routeData       = new RouteData(context.RouteData);
                var matchingActions = new MatchingActionSequence(finalMatches, routeData);

                selectionResult.AddMatches(matchingActions);
                selectionResult.TrySetBestMatch(matchingActions.BestMatch);
            }

            // note: even though we may have had a successful match, this method could be called multiple times. the final decision
            // is made by the IApiVersionRoutePolicy. we return here to make sure all candidates have been considered at least once.
            selectionResult.EndIteration();
            return(null);
        }
示例#2
0
        void AppendPossibleMatches(IReadOnlyList <ActionDescriptor> matches, RouteContext context, ActionSelectionResult result)
        {
            Contract.Requires(matches != null);
            Contract.Requires(context != null);
            Contract.Requires(result != null);

            if (matches.Count == 0)
            {
                return;
            }

            var routeData       = new RouteData(context.RouteData);
            var matchingActions = new MatchingActionSequence(matches, routeData);

            result.AddMatches(matchingActions);
            result.TrySetBestMatch(matchingActions.BestMatch);
        }