internal override ControllerSelectionResult SelectController(ApiVersionControllerAggregator aggregator)
        {
            Contract.Requires(aggregator != null);
            Contract.Ensures(Contract.Result <ControllerSelectionResult>() != null);

            var request          = aggregator.Request;
            var requestedVersion = aggregator.RequestedApiVersion;
            var controllerName   = aggregator.ControllerName;
            var result           = new ControllerSelectionResult()
            {
                RequestedVersion = requestedVersion,
                ControllerName   = controllerName,
                HasCandidates    = aggregator.HasConventionBasedRoutes
            };

            if (!result.HasCandidates)
            {
                return(result);
            }

            var ambiguousException       = new Lazy <Exception>(() => CreateAmbiguousControllerException(aggregator.RouteData.Route, controllerName, controllerTypeCache.GetControllerTypes(controllerName)));
            var versionNeutralController = result.Controller = GetVersionNeutralController(aggregator.ConventionRouteCandidates, ambiguousException);

            if (requestedVersion == null)
            {
                if (!AssumeDefaultVersionWhenUnspecified)
                {
                    return(result);
                }

                requestedVersion = ApiVersionSelector.SelectVersion(request, aggregator.AllVersions);

                if (requestedVersion == null)
                {
                    return(result);
                }
            }

            var versionedController = GetVersionedController(aggregator, requestedVersion, ambiguousException);

            if (versionedController == null)
            {
                return(result);
            }

            if (versionNeutralController != null)
            {
                throw ambiguousException.Value;
            }

            request.ApiVersionProperties().ApiVersion = requestedVersion;
            result.Controller = versionedController;

            return(result);
        }
Example #2
0
        internal override ControllerSelectionResult SelectController(ApiVersionControllerAggregator aggregator)
        {
            Contract.Requires(aggregator != null);
            Contract.Ensures(Contract.Result <ControllerSelectionResult>() != null);

            var request          = aggregator.Request;
            var requestedVersion = aggregator.RequestedApiVersion;
            var result           = new ControllerSelectionResult()
            {
                HasCandidates    = aggregator.HasAttributeBasedRoutes,
                RequestedVersion = requestedVersion,
            };

            if (!result.HasCandidates)
            {
                return(result);
            }

            var versionNeutralController = result.Controller = GetVersionNeutralController(aggregator.DirectRouteCandidates);

            if (requestedVersion == null)
            {
                if (!AssumeDefaultVersionWhenUnspecified)
                {
                    return(result);
                }

                requestedVersion = ApiVersionSelector.SelectVersion(request, aggregator.AllVersions);

                if (requestedVersion == null)
                {
                    return(result);
                }
            }

            var versionedController = GetVersionedController(aggregator, requestedVersion);

            if (versionedController == null)
            {
                return(result);
            }

            if (versionNeutralController != null)
            {
                throw CreateAmbiguousControllerException(new[] { versionNeutralController, versionedController });
            }

            request.ApiVersionProperties().RequestedApiVersion = requestedVersion;
            result.RequestedVersion = requestedVersion;
            result.Controller       = versionedController;

            return(result);
        }
        /// <summary>
        /// Returns the set of best matching actions.
        /// </summary>
        /// <param name="context">The <see cref="ActionSelectionContext">context</see> to select the actions from.</param>
        /// <returns>A <see cref="IReadOnlyList{T}">read-only list</see> of the best matching <see cref="ActionDescriptor">actions</see>.</returns>
        protected virtual IReadOnlyList <ActionDescriptor> SelectBestActions(ActionSelectionContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var requestedVersion = context.RequestedVersion;

            if (requestedVersion == null)
            {
                if (Options.AssumeDefaultVersionWhenUnspecified)
                {
                    context.RequestedVersion = requestedVersion = ApiVersionSelector.SelectVersion(context.HttpContext.Request, context.AllVersions);
                }
            }

            var bestMatches     = new HashSet <ActionDescriptor>();
            var implicitMatches = new HashSet <ActionDescriptor>();

            for (var i = 0; i < context.MatchingActions.Count; i++)
            {
                var action = context.MatchingActions[i];

                switch (action.MappingTo(requestedVersion))
                {
                case Explicit:
                    bestMatches.Add(action);
                    break;

                case Implicit:
                    implicitMatches.Add(action);
                    break;
                }
            }

            if (bestMatches.Count == 0)
            {
                bestMatches.AddRange(implicitMatches);
            }

            if (bestMatches.Count == 1)
            {
                var model = bestMatches.Single().GetApiVersionModel();

                if (model.IsApiVersionNeutral)
                {
                    bestMatches.AddRange(implicitMatches);
                }
            }

            return(bestMatches.ToArray());
        }
Example #4
0
        /// <summary>
        /// Returns the set of best matching actions.
        /// </summary>
        /// <param name="context">The <see cref="ActionSelectionContext">context</see> to select the actions from.</param>
        /// <returns>A <see cref="IReadOnlyList{T}">read-only list</see> of the best matching <see cref="ActionDescriptor">actions</see>.</returns>
        protected virtual IReadOnlyList <ActionDescriptor> SelectBestActions(ActionSelectionContext context)
        {
            Arg.NotNull(context, nameof(context));
            Contract.Ensures(Contract.Result <IReadOnlyList <ActionDescriptor> >() != null);

            var bestMatches = new List <ActionDescriptor>(context.MatchingActions.Count);

            bestMatches.AddRange(MatchVersionNeutralActions(context));

            if (context.RequestedVersion == null)
            {
                if (!Options.AssumeDefaultVersionWhenUnspecified)
                {
                    return(bestMatches);
                }

                context.RequestedVersion = ApiVersionSelector.SelectVersion(context.HttpContext.Request, context.AllVersions);

                if (context.RequestedVersion == null)
                {
                    return(bestMatches);
                }
            }

            var implicitMatches = new List <ActionDescriptor>();
            var explicitMatches = from action in context.MatchingActions
                                  let model = action.GetProperty <ApiVersionModel>()
                                              where ActionIsSatisfiedBy(action, model, context.RequestedVersion, implicitMatches)
                                              select action;

            bestMatches.AddRange(explicitMatches);

            if (bestMatches.Count == 0)
            {
                bestMatches.AddRange(implicitMatches);
            }

            if (bestMatches.Count != 1)
            {
                return(bestMatches);
            }

            if (bestMatches[0].IsApiVersionNeutral())
            {
                bestMatches.AddRange(implicitMatches);
            }

            return(bestMatches);
        }