internal ControllerSelectionContext(
     HttpRequestMessage request,
     Func <HttpRequestMessage, string?> controllerName,
     Lazy <ConcurrentDictionary <string, HttpControllerDescriptorGroup> > controllerInfoCache)
 {
     Request                   = request;
     requestProperties         = request.ApiVersionProperties();
     this.controllerName       = new Lazy <string?>(() => controllerName(Request));
     this.controllerInfoCache  = controllerInfoCache;
     RouteData                 = request.GetRouteData();
     conventionRouteCandidates = new Lazy <CandidateAction[]?>(GetConventionRouteCandidates);
     directRouteCandidates     = new Lazy <CandidateAction[]?>(() => RouteData?.GetDirectRouteCandidates());
     allVersions               = new Lazy <ApiVersionModel>(CreateAggregatedModel);
 }
Example #2
0
        /// <summary>
        /// Gets the current API versioning request properties.
        /// </summary>
        /// <param name="request">The <see cref="HttpRequestMessage">request</see> to get the API versioning properties for.</param>
        /// <returns>The current <see cref="ApiVersionRequestProperties">API versioning properties</see>.</returns>
        public static ApiVersionRequestProperties ApiVersionProperties(this HttpRequestMessage request)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (!request.Properties.TryGetValue(ApiVersionPropertiesKey, out ApiVersionRequestProperties properties))
            {
                request.Properties[ApiVersionPropertiesKey] = properties = new ApiVersionRequestProperties(request);
            }

            return(properties);
        }
        /// <summary>
        /// Gets the current API versioning request properties.
        /// </summary>
        /// <param name="request">The <see cref="HttpRequestMessage">request</see> to get the API versioning properties for.</param>
        /// <returns>The current <see cref="ApiVersionRequestProperties">API versioning properties</see>.</returns>
        public static ApiVersionRequestProperties ApiVersionProperties(this HttpRequestMessage request)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (!request.Properties.TryGetValue(ApiVersionPropertiesKey, out ApiVersionRequestProperties properties))
            {
                var forceRouteConstraintEvaluation = !request.Properties.ContainsKey(RoutingContextKey);

                request.Properties[ApiVersionPropertiesKey] = properties = new ApiVersionRequestProperties(request);

                if (forceRouteConstraintEvaluation)
                {
                    request.GetConfiguration()?.Routes.GetRouteData(request);
                }
            }

            return(properties);
        }
        public void http_context_should_return_raw_api_version_from_query_string_without_configuration()
        {
            // arrange
            var query       = new Mock <IQueryCollection>();
            var request     = new Mock <HttpRequest>();
            var httpContext = new Mock <HttpContext>();
            var items       = new Dictionary <object, object>();

            query.SetupGet(q => q["api-version"]).Returns(new StringValues("42.0"));
            request.SetupGet(r => r.Query).Returns(query.Object);
            httpContext.SetupGet(c => c.Request).Returns(request.Object);
            httpContext.SetupProperty(c => c.RequestServices, Mock.Of <IServiceProvider>());
            httpContext.SetupProperty(c => c.Items, items);
            items["MS_ApiVersionRequestProperties"] = new ApiVersionRequestProperties(httpContext.Object);

            // act
            var result = httpContext.Object.ApiVersionProperties().RawApiVersion;

            // assert
            result.Should().Be("42.0");
        }
        /// <summary>
        /// Gets the current API versioning request properties.
        /// </summary>
        /// <param name="request">The <see cref="HttpRequestMessage">request</see> to get the API versioning properties for.</param>
        /// <returns>The current <see cref="ApiVersionRequestProperties">API versioning properties</see>.</returns>
        public static ApiVersionRequestProperties ApiVersionProperties(this HttpRequestMessage request)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (request.Properties.TryGetValue(ApiVersionPropertiesKey, out ApiVersionRequestProperties properties))
            {
                return(properties);
            }

            var forceRouteConstraintEvaluation = !request.Properties.ContainsKey(RoutingContextKey);

            request.Properties[ApiVersionPropertiesKey] = properties = new ApiVersionRequestProperties(request);

            if (forceRouteConstraintEvaluation && request.GetConfiguration() is HttpConfiguration configuration)
            {
                // HACK: do NOT use 'HttpRouteCollection.GetRouteData' because it can result in a LockRecursionException when hosted on IIS
                // REF: https://github.com/microsoft/referencesource/blob/master/System.Web/Routing/RouteCollection.cs#L159
                var routes          = configuration.Routes;
                var context         = request.GetRequestContext();
                var virtualPathRoot = context?.VirtualPathRoot ?? routes.VirtualPathRoot ?? string.Empty;

                // HACK: do NOT use a normal 'for' loop here because the IIS implementation does not support indexing
                foreach (var route in routes)
                {
                    if (route.GetRouteData(virtualPathRoot, request) is not null)
                    {
                        break;
                    }
                }
            }

            return(properties);
        }
        static ApiVersion GetRequestedApiVersionOrReturnBadRequest(HttpRequestMessage request, ApiVersionRequestProperties properties)
        {
            Contract.Requires(request != null);
            Contract.Requires(properties != null);

            try
            {
                return(properties.RequestedApiVersion);
            }
            catch (AmbiguousApiVersionException ex)
            {
                var error = new ODataError()
                {
                    ErrorCode = "AmbiguousApiVersion", Message = ex.Message
                };
                throw new HttpResponseException(request.CreateResponse(BadRequest, error));
            }
        }