/// <summary>
        /// Gets the <see cref="HttpRequestMessageProperties"/> instance containing OData methods and properties
        /// for given <see cref="HttpRequestMessage"/>.
        /// </summary>
        /// <param name="request">The request of interest.</param>
        /// <returns>
        /// An object through which OData methods and properties for given <paramref name="request"/> are available.
        /// </returns>
        public static HttpRequestMessageProperties ODataProperties(this HttpRequestMessage request)
        {
            if (request == null)
            {
                throw Error.ArgumentNull("request");
            }

            // Cache HttpRequestMessageProperties value to avoid lots of identical objects with no instance data.
            HttpRequestMessageProperties properties;
            object value;
            if (request.Properties.TryGetValue(PropertiesKey, out value))
            {
                properties = value as HttpRequestMessageProperties;
                Contract.Assert(properties != null);
            }
            else
            {
                properties = new HttpRequestMessageProperties(request);

                // Avoid race conditions: Do not use Add().  Worst case here is an extra HttpRequestMessageProperties
                // instance which will soon go out of scope.
                request.Properties[PropertiesKey] = properties;
            }

            return properties;
        }
        private static SelectExpandClause GetSelectExpandClause(
            IEdmType edmType,
            ODataQueryOptions queryOptions,
            EntityPropertyFilterConfig.PropertySet propertySet,
            HttpRequestMessageProperties oDataProperties,
            IEnumerable <ExpandedNavigationSelectItem> selectItems = null)
        {
            if (propertySet == null)
            {
                return(null);
            }

            var selectExpandDictionary =
                new Dictionary <string, string> {
                { "$select", string.Join(", ", propertySet.Properties) },
            };

            if (selectItems != null)
            {
                selectExpandDictionary.Add("$expand", string.Join(", ", selectItems.Select(s => s.PathToNavigationProperty.FirstSegment.Identifier)));
            }

            var parser = new ODataQueryOptionParser(
                queryOptions.Context.Model,
                edmType,
                oDataProperties.Path.NavigationSource,
                selectExpandDictionary);

            return(parser.ParseSelectAndExpand());
        }
        public static ODataQueryOptions <TDto> GetODataQueryOptions <TDto>(this HttpRequestMessage request)
        {
            HttpRequestMessageProperties requestODataProps        = request.ODataProperties();
            ODataQueryContext            currentOdataQueryContext = new ODataQueryContext(request.GetModel(), typeof(TDto), requestODataProps.Path);
            ODataQueryOptions <TDto>     currentOdataQueryOptions = new ODataQueryOptions <TDto>(currentOdataQueryContext, request);

            return(currentOdataQueryOptions);
        }
Beispiel #4
0
        protected virtual ODataQueryOptions <TDto> GetODataQueryOptions()
        {
            HttpRequestMessageProperties requestODataProps        = Request.ODataProperties();
            ODataQueryContext            currentOdataQueryContext = new ODataQueryContext(Request.GetModel(), typeof(TDto).GetTypeInfo(), requestODataProps.Path);
            ODataQueryOptions <TDto>     currentOdataQueryOptions = new ODataQueryOptions <TDto>(currentOdataQueryContext, Request);

            return(currentOdataQueryOptions);
        }
        public static ODataQueryOptions GetODataQueryOptions(this HttpRequestMessage request, TypeInfo dtoType)
        {
            HttpRequestMessageProperties requestODataProps        = request.ODataProperties();
            ODataQueryContext            currentOdataQueryContext = new ODataQueryContext(request.GetModel(), dtoType, requestODataProps.Path);
            ODataQueryOptions            currentOdataQueryOptions = new ODataQueryOptions(currentOdataQueryContext, request);

            return(currentOdataQueryOptions);
        }
Beispiel #6
0
        private IQueryable GetQuery()
        {
            ODataPath path = this.GetPath();

            RestierQueryBuilder builder   = new RestierQueryBuilder(this.Api, path);
            IQueryable          queryable = builder.BuildQuery();

            this.shouldReturnCount   = builder.IsCountPathSegmentPresent;
            this.shouldWriteRawValue = builder.IsValuePathSegmentPresent;
            if (queryable == null)
            {
                throw new HttpResponseException(
                          this.Request.CreateErrorResponse(
                              HttpStatusCode.NotFound,
                              Resources.ResourceNotFound));
            }

            if (this.shouldWriteRawValue)
            {
                // Query options don't apply to $value.
                return(queryable);
            }

            HttpRequestMessageProperties properties   = this.Request.ODataProperties();
            ODataQueryContext            queryContext =
                new ODataQueryContext(properties.Model, queryable.ElementType, path);
            ODataQueryOptions queryOptions = new ODataQueryOptions(queryContext, this.Request);

            // TODO GitHubIssue#41 : Ensure stable ordering for query
            ODataQuerySettings settings = Api.Context.GetApiService <ODataQuerySettings>();

            if (this.shouldReturnCount)
            {
                // Query options other than $filter and $search don't apply to $count.
                queryable = queryOptions.ApplyTo(
                    queryable, settings, AllowedQueryOptions.All ^ AllowedQueryOptions.Filter);
                return(queryable);
            }

            if (queryOptions.Count != null)
            {
                RestierQueryExecutorOptions queryExecutorOptions =
                    Api.Context.GetApiService <RestierQueryExecutorOptions>();
                queryExecutorOptions.IncludeTotalCount = queryOptions.Count.Value;
                queryExecutorOptions.SetTotalCount     = value => properties.TotalCount = value;
            }

            // Validate query before apply, and query setting like MaxExpansionDepth can be customized here
            ODataValidationSettings validationSettings = Api.Context.GetApiService <ODataValidationSettings>();

            queryOptions.Validate(validationSettings);

            // Entity count can NOT be evaluated at this point of time because the source
            // expression is just a placeholder to be replaced by the expression sourcer.
            queryable = queryOptions.ApplyTo(queryable, settings, AllowedQueryOptions.Count);

            return(queryable);
        }
Beispiel #7
0
        /// <summary>
        /// Initializes a new instance of the WebApiContext class.
        /// </summary>
        /// <param name="context">The inner context.</param>
        public WebApiContext(HttpRequestMessageProperties context)
        {
            if (context == null)
            {
                throw Error.ArgumentNull("context");
            }

            this.innerContext = context;
        }
        /// <summary>
        /// Determines whether this instance equals a specified route.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <param name="route">The route to compare.</param>
        /// <param name="parameterName">The name of the parameter.</param>
        /// <param name="values">A list of parameter values.</param>
        /// <param name="routeDirection">The route direction.</param>
        /// <returns>
        /// True if this instance equals a specified route; otherwise, false.
        /// </returns>
        /// <remarks>This signature uses types that are AspNet-specific.</remarks>
        public virtual bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary <string, object> values, HttpRouteDirection routeDirection)
        {
            if (request == null)
            {
                throw Error.ArgumentNull("request");
            }

            if (values == null)
            {
                throw Error.ArgumentNull("values");
            }

            if (routeDirection == HttpRouteDirection.UriResolution)
            {
                ODataPath path = null;

                object oDataPathValue;
                if (values.TryGetValue(ODataRouteConstants.ODataPath, out oDataPathValue))
                {
                    string requestLeftPart = request.RequestUri.GetLeftPart(UriPartial.Path);
                    string queryString     = request.RequestUri.Query;

                    path = GetODataPath(oDataPathValue as string, requestLeftPart, queryString, () => request.CreateRequestContainer(RouteName));
                }

                if (path != null)
                {
                    // Set all the properties we need for routing, querying, formatting
                    HttpRequestMessageProperties properties = request.ODataProperties();
                    properties.Path      = path;
                    properties.RouteName = RouteName;

                    if (!values.ContainsKey(ODataRouteConstants.Controller))
                    {
                        // Select controller name using the routing conventions
                        string controllerName = SelectControllerName(path, request);
                        if (controllerName != null)
                        {
                            values[ODataRouteConstants.Controller] = controllerName;
                        }
                    }

                    return(true);
                }

                // The request doesn't match this route so dispose the request container.
                request.DeleteRequestContainer(true);
                return(false);
            }
            else
            {
                // This constraint only applies to URI resolution
                return(true);
            }
        }
Beispiel #9
0
        public IHttpActionResult Count(
            [ModelBinder] ODataQueryOptions queryOptions,
            [ModelBinder] HttpRequestMessageProperties oDataProperties,
            [ModelBinder] IDataService dataService)
        {
            var edmTypeReference  = oDataProperties.Path.EntitySet.ElementType;
            var edmCollectionType = new EdmCollectionType(new EdmEntityTypeReference(edmTypeReference, true));

            var count = dataService.Count(edmCollectionType, queryOptions);

            return(new OkStringContentResult(this, count.ToString()));
        }
        public static ODataQueryOptions <TDto> GetODataQueryOptions <TDto>(this HttpRequestMessage request)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            HttpRequestMessageProperties requestODataProps        = request.ODataProperties();
            ODataQueryContext            currentOdataQueryContext = new ODataQueryContext(request.GetModel(), typeof(TDto), requestODataProps.Path);
            ODataQueryOptions <TDto>     currentOdataQueryOptions = new ODataQueryOptions <TDto>(currentOdataQueryContext, request);

            return(currentOdataQueryOptions);
        }
Beispiel #11
0
        internal static ODataVersion GetODataResponseVersion(HttpRequestMessage request)
        {
            if (request == null)
            {
                return(ODataVersionConstraint.DefaultODataVersion);
            }

            HttpRequestMessageProperties properties = request.ODataProperties();

            return(properties.ODataMaxServiceVersion ??
                   properties.ODataMinServiceVersion ??
                   properties.ODataServiceVersion ??
                   ODataVersionConstraint.DefaultODataVersion);
        }
Beispiel #12
0
        internal static ODataVersion GetODataResponseVersion(HttpRequestMessage request)
        {
            // OData protocol requires that you send the minimum version that the client needs to know to
            // understand the response. There is no easy way we can figure out the minimum version that the client
            // needs to understand our response. We send response headers much ahead generating the response. So if
            // the requestMessage has a OData-MaxVersion, tell the client that our response is of the same
            // version; else use the DataServiceVersionHeader. Our response might require a higher version of the
            // client and it might fail. If the client doesn't send these headers respond with the default version
            // (V4).
            HttpRequestMessageProperties properties = request.ODataProperties();

            return(properties.ODataMaxServiceVersion ??
                   properties.ODataServiceVersion ??
                   HttpRequestMessageProperties.DefaultODataVersion);
        }
        private static HttpRequestMessage SetupRequest(HttpMethod method, string odataPath, IEdmModel edmModel = null)
        {
            HttpRequestMessage request;

            request = new HttpRequestMessage(method, "http://host/any");
            IEdmModel model = edmModel ?? SetupModel();

            request.EnableODataDependencyInjectionSupport(model);
            HttpRequestMessageProperties properties = request.ODataProperties();

            properties.Path = request.GetRequestContainer()
                              .GetRequiredService <IODataPathHandler>()
                              .Parse(model, "http://localhost/any", odataPath);
            return(request);
        }
Beispiel #14
0
        public IEdmEntityObject Get(string key, [ModelBinder] HttpRequestMessageProperties oDataProperties, [ModelBinder] IDataService dataService)
        {
            ODataPath      path       = oDataProperties.Path;
            IEdmEntityType entityType = path.EdmType as IEdmEntityType;

            var entity = dataService.Get(key, entityType);

            // make sure return 404 if key does not exist in database
            if (entity == null)
            {
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }

            return(entity);
        }
Beispiel #15
0
        private static HttpRequestMessage SetupRequest(HttpMethod method, string odataPath)
        {
            HttpRequestMessage request;
            HttpConfiguration  configuration = new HttpConfiguration();

            request = new HttpRequestMessage(method, "http://host/any");
            request.SetConfiguration(configuration);
            HttpRequestMessageProperties properties = request.ODataProperties();
            IEdmModel model = SetupModel();

            properties.Model       = model;
            properties.PathHandler = new DefaultODataPathHandler();
            properties.Path        = properties.PathHandler.Parse(model, odataPath);
            return(request);
        }
Beispiel #16
0
        private ODataPath GetPath()
        {
            HttpRequestMessageProperties properties = this.Request.ODataProperties();

            if (properties == null)
            {
                throw new InvalidOperationException(Resources.InvalidODataInfoInRequest);
            }

            ODataPath path = properties.Path;

            if (path == null)
            {
                throw new InvalidOperationException(Resources.InvalidEmptyPathInRequest);
            }

            return(path);
        }
        public static ODataQueryOptions GetODataQueryOptions(this HttpRequestMessage request, TypeInfo dtoType)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (dtoType == null)
            {
                throw new ArgumentNullException(nameof(dtoType));
            }

            HttpRequestMessageProperties requestODataProps        = request.ODataProperties();
            ODataQueryContext            currentOdataQueryContext = new ODataQueryContext(request.GetModel(), dtoType, requestODataProps.Path);
            ODataQueryOptions            currentOdataQueryOptions = new ODataQueryOptions(currentOdataQueryContext, request);

            return(currentOdataQueryOptions);
        }
Beispiel #18
0
        /// <summary>
        /// Handles a GET request to query entities.
        /// </summary>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The task object that contains the response message.</returns>
        public async Task <HttpResponseMessage> Get(
            CancellationToken cancellationToken)
        {
            HttpRequestMessageProperties odataProperties = this.Request.ODataProperties();
            ODataPath path = odataProperties.Path;

            if (path == null)
            {
                throw new InvalidOperationException(Resources.ControllerRequiresPath);
            }

            IQueryable   queryable    = this.GetQuery();
            QueryRequest queryRequest = new QueryRequest(queryable)
            {
                ShouldReturnCount = this.shouldReturnCount
            };
            QueryResult queryResult = await Api.QueryAsync(queryRequest, cancellationToken);

            this.Request.Properties[ETagGetterKey] = this.Api.Context.GetProperty(ETagGetterKey);

            return(this.CreateQueryResponse(queryResult.Results.AsQueryable(), path.EdmType));
        }
Beispiel #19
0
        protected virtual string CreateODataLink(string odataModule = null, string controller = null, string action = null, IDictionary <string, object> routeValues = null)
        {
            HttpRequestMessageProperties odataProps = Request.ODataProperties();

            if (odataModule == null)
            {
                odataModule = odataProps.RouteName.Replace("-odata", string.Empty);
            }
            if (controller == null)
            {
                controller = odataProps.Path.Segments.OfType <EntitySetSegment>().ExtendedSingle($"Finding entity set name from {odataProps.Path}").EntitySet.Name;
            }
            if (action == null)
            {
                action = odataProps.Path.Segments.OfType <OperationSegment>().ExtendedSingle($"Finding operation segment from {odataProps.Path}").Operations.ExtendedSingle($"Finding operation name from {odataProps.Path}").Name;
            }

            string url = RequestContext.Url.Link($"{odataModule}-odata", new { odataPath = $"{controller}/{action}", controller, action });

            url += "(";

            if (routeValues != null)
            {
                url += string.Join(",", routeValues.Select(routeValueItem =>
                {
                    object value = routeValueItem.Value;
                    if (value is string strValue)
                    {
                        value = HttpUtility.UrlEncode($"'{strValue}'");
                    }
                    return($"{routeValueItem.Key}={value}");
                }));
            }

            url += ")";

            return(url);
        }
        /// <summary>
        /// Initializes a new instance of the WebApiRequestMessage class.
        /// </summary>
        /// <param name="request">The inner request.</param>
        public WebApiRequestMessage(HttpRequestMessage request)
        {
            if (request == null)
            {
                throw Error.ArgumentNull("request");
            }

            this.innerRequest = request;

            HttpRequestMessageProperties context = request.ODataProperties();

            if (context != null)
            {
                this.Context = new WebApiContext(context);
            }

            HttpConfiguration configuration = request.GetConfiguration();

            if (configuration != null)
            {
                this.Options = new WebApiOptions(configuration);
            }
        }
Beispiel #21
0
        public EdmEntityObjectCollection Get(
            [ModelBinder] ODataQueryOptions queryOptions,
            [ModelBinder] HttpRequestMessageProperties oDataProperties,
            [ModelBinder] IDataService dataService)
        {
            var collectionType = oDataProperties.Path.EdmType as IEdmCollectionType;

            // make $count works
            if (queryOptions.InlineCount != null)
            {
                oDataProperties.TotalCount = dataService.Count(collectionType, queryOptions);
            }

            //make $select works
            if (queryOptions.SelectExpand != null)
            {
                oDataProperties.SelectExpandClause = queryOptions.SelectExpand.SelectExpandClause;
            }

            var collection = dataService.Get(collectionType, queryOptions);

            return(collection);
        }
        public override async Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
        {
            if (actionExecutedContext?.Response?.Content is ObjectContent &&
                actionExecutedContext?.Response?.IsSuccessStatusCode == true)
            {
                ObjectContent objContent = ((ObjectContent)(actionExecutedContext.Response.Content));

                if (objContent.Value == null)
                {
                    actionExecutedContext.Response.StatusCode = HttpStatusCode.NoContent;
                    actionExecutedContext.Response.Content    = null;
                }
                else
                {
                    TypeInfo actionReturnType = objContent.Value.GetType().GetTypeInfo();

                    if (typeof(string) != actionReturnType && typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(actionReturnType))
                    {
                        bool isIQueryable = typeof(IQueryable).GetTypeInfo().IsAssignableFrom(actionReturnType);

                        TypeInfo queryElementType = actionReturnType.HasElementType ? actionReturnType.GetElementType().GetTypeInfo() : actionReturnType.GetGenericArguments().First() /* Why not calling Single() ? http://stackoverflow.com/questions/41718323/why-variable-of-type-ienumerablesomething-gettype-getgenericargsuments-c */.GetTypeInfo();
                        IDataProviderSpecificMethodsProvider dataProviderSpecificMethodsProvider = null;

                        if (isIQueryable == true)
                        {
                            IEnumerable <IDataProviderSpecificMethodsProvider> dataProviderSpecificMethodsProviders = actionExecutedContext.Request.GetOwinContext().GetDependencyResolver().ResolveAll <IDataProviderSpecificMethodsProvider>();
                            dataProviderSpecificMethodsProvider = (IDataProviderSpecificMethodsProvider)typeof(ODataEnableQueryAttribute).GetMethod(nameof(FindDataProviderSpecificMethodsProvider)).MakeGenericMethod(queryElementType).Invoke(this, new object[] { objContent.Value, dataProviderSpecificMethodsProviders });
                        }
                        else
                        {
                            objContent.Value = typeof(ODataEnableQueryAttribute).GetMethod(nameof(ToQueryable)).MakeGenericMethod(queryElementType).Invoke(this, new object[] { objContent.Value });
                        }

                        HttpRequestMessageProperties requestODataProps        = actionExecutedContext.Request.ODataProperties();
                        ODataQueryContext            currentOdataQueryContext = new ODataQueryContext(actionExecutedContext.Request.GetModel(), queryElementType, requestODataProps.Path);
                        ODataQueryOptions            currentOdataQueryOptions = new ODataQueryOptions(currentOdataQueryContext, actionExecutedContext.Request);
                        ODataQuerySettings           globalODataQuerySettings = new ODataQuerySettings
                        {
                            EnableConstantParameterization = this.EnableConstantParameterization,
                            EnsureStableOrdering           = this.EnsureStableOrdering,
                            HandleNullPropagation          = this.HandleNullPropagation,
                            PageSize = this.DefaultPageSize
                        };

                        ValidateQuery(actionExecutedContext.Request, currentOdataQueryOptions);

                        int?currentQueryPageSize = currentOdataQueryOptions?.Top?.Value;
                        int?globalQuerypageSize  = globalODataQuerySettings.PageSize;
                        int?takeCount            = null;
                        int?skipCount            = currentOdataQueryOptions?.Skip?.Value;

                        if (currentQueryPageSize.HasValue)
                        {
                            takeCount = currentQueryPageSize.Value;
                        }
                        else if (globalQuerypageSize.HasValue == true)
                        {
                            takeCount = globalQuerypageSize.Value;
                        }
                        else
                        {
                            takeCount = null;
                        }

                        globalODataQuerySettings.PageSize = null; // ApplyTo will enumerates the query for values other than null. We are gonna apply take in ToList & ToListAsync methods.

                        if (currentOdataQueryOptions.Filter != null)
                        {
                            objContent.Value = currentOdataQueryOptions.Filter.ApplyTo(query: (IQueryable)objContent.Value, querySettings: globalODataQuerySettings);
                        }

                        if (currentOdataQueryOptions.Count?.Value == true && takeCount.HasValue == true)
                        {
                            long count = default(long);
                            if (dataProviderSpecificMethodsProvider != null)
                            {
                                count = await(Task <long>) typeof(ODataEnableQueryAttribute).GetMethod(nameof(GetCountAsync)).MakeGenericMethod(queryElementType).Invoke(this, new object[] { objContent.Value, dataProviderSpecificMethodsProvider, cancellationToken });
                            }
                            else
                            {
                                count = (long)typeof(ODataEnableQueryAttribute).GetMethod(nameof(GetCount)).MakeGenericMethod(queryElementType).Invoke(this, new object[] { objContent.Value });
                            }

                            actionExecutedContext.Request.Properties["System.Web.OData.TotalCountFunc"] = new Func <long>(() => count);
                        }

                        objContent.Value = currentOdataQueryOptions.ApplyTo(query: (IQueryable)objContent.Value, querySettings: globalODataQuerySettings, ignoreQueryOptions: AllowedQueryOptions.Filter | AllowedQueryOptions.Skip | AllowedQueryOptions.Top);

                        if (currentOdataQueryOptions.SelectExpand != null)
                        {
                            queryElementType = objContent.Value.GetType().GetTypeInfo().GetGenericArguments().Single().GetTypeInfo();
                        }

                        if (dataProviderSpecificMethodsProvider != null)
                        {
                            objContent.Value = await(Task <object>) typeof(ODataEnableQueryAttribute).GetMethod(nameof(ToListAsync)).MakeGenericMethod(queryElementType).Invoke(this, new object[] { objContent.Value, dataProviderSpecificMethodsProvider, takeCount, skipCount, cancellationToken });
                        }
                        else
                        {
                            objContent.Value = typeof(ODataEnableQueryAttribute).GetMethod(nameof(ToList)).MakeGenericMethod(queryElementType).Invoke(this, new object[] { objContent.Value, takeCount, skipCount });
                        }

                        if (currentOdataQueryOptions.Count?.Value == true && takeCount.HasValue == false)
                        {
                            // We've no paging becuase there is no global config for max top and there is no top specified by the client's request, so the retured result of query's length is equivalent to total count of the query
                            long count = ((IList)objContent.Value).Count;
                            actionExecutedContext.Request.Properties["System.Web.OData.TotalCountFunc"] = new Func <long>(() => count);
                        }
                    }
                }
            }
        }
Beispiel #23
0
        private IQueryable ApplyQueryOptions(
            IQueryable queryable, ODataPath path, bool applyCount, out ETag etag)
        {
            etag = null;

            if (this.shouldWriteRawValue)
            {
                // Query options don't apply to $value.
                return(queryable);
            }

            HttpRequestMessageProperties properties = this.Request.ODataProperties();
            var model = Api.GetModelAsync().Result;
            ODataQueryContext queryContext =
                new ODataQueryContext(model, queryable.ElementType, path);
            ODataQueryOptions queryOptions = new ODataQueryOptions(queryContext, this.Request);

            // Get etag for query request
            if (queryOptions.IfMatch != null)
            {
                etag = queryOptions.IfMatch;
            }
            else if (queryOptions.IfNoneMatch != null)
            {
                etag = queryOptions.IfNoneMatch;
            }

            // TODO GitHubIssue#41 : Ensure stable ordering for query
            ODataQuerySettings settings = Api.GetApiService <ODataQuerySettings>();

            if (this.shouldReturnCount)
            {
                // Query options other than $filter and $search don't apply to $count.
                queryable = queryOptions.ApplyTo(
                    queryable, settings, AllowedQueryOptions.All ^ AllowedQueryOptions.Filter);
                return(queryable);
            }

            if (queryOptions.Count != null && !applyCount)
            {
                RestierQueryExecutorOptions queryExecutorOptions =
                    Api.GetApiService <RestierQueryExecutorOptions>();
                queryExecutorOptions.IncludeTotalCount = queryOptions.Count.Value;
                queryExecutorOptions.SetTotalCount     = value => properties.TotalCount = value;
            }

            // Validate query before apply, and query setting like MaxExpansionDepth can be customized here
            ODataValidationSettings validationSettings = Api.GetApiService <ODataValidationSettings>();

            queryOptions.Validate(validationSettings);

            // Entity count can NOT be evaluated at this point of time because the source
            // expression is just a placeholder to be replaced by the expression sourcer.
            if (!applyCount)
            {
                queryable = queryOptions.ApplyTo(queryable, settings, AllowedQueryOptions.Count);
            }
            else
            {
                queryable = queryOptions.ApplyTo(queryable, settings);
            }

            return(queryable);
        }
Beispiel #24
0
        public override bool Match(
            HttpRequestMessage request,
            IHttpRoute route,
            string parameterName,
            IDictionary <string, object> values,
            HttpRouteDirection routeDirection)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            if (values == null)
            {
                throw new ArgumentNullException("values");
            }

            if (routeDirection != HttpRouteDirection.UriResolution)
            {
                return(true);
            }

            object odataPathRouteValue;

            if (!values.TryGetValue(ODataRouteConstants.ODataPath, out odataPathRouteValue))
            {
                return(false);
            }

            string odataPath = odataPathRouteValue as string ?? string.Empty;

            ODataPath path;
            IEdmModel model;

            try
            {
                request.Properties[Constants.CustomODataPath] = odataPath;
                model     = EdmModelProvider(request);
                odataPath = (string)request.Properties[Constants.CustomODataPath];
                path      = PathHandler.Parse(model, odataPath);
            }
            catch (ODataException)
            {
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }

            if (path == null)
            {
                return(false);
            }

            HttpRequestMessageProperties odataProperties = request.ODataProperties();

            odataProperties.Model              = model;
            odataProperties.PathHandler        = PathHandler;
            odataProperties.Path               = path;
            odataProperties.RouteName          = RouteName;
            odataProperties.RoutingConventions = RoutingConventions;

            if (values.ContainsKey(ODataRouteConstants.Controller))
            {
                return(true);
            }

            string controllerName = SelectControllerName(path, request);

            if (controllerName != null)
            {
                values[ODataRouteConstants.Controller] = controllerName;
            }

            return(true);
        }
        /// <summary>
        /// Determines whether this instance equals a specified route.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <param name="route">The route to compare.</param>
        /// <param name="parameterName">The name of the parameter.</param>
        /// <param name="values">A list of parameter values.</param>
        /// <param name="routeDirection">The route direction.</param>
        /// <returns>
        /// True if this instance equals a specified route; otherwise, false.
        /// </returns>
        /// <remarks>This signature uses types that are AspNet-specific.</remarks>
        public virtual bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary <string, object> values, HttpRouteDirection routeDirection)
        {
            if (request == null)
            {
                throw Error.ArgumentNull("request");
            }

            if (values == null)
            {
                throw Error.ArgumentNull("values");
            }

            if (routeDirection == HttpRouteDirection.UriResolution)
            {
                ODataPath path = null;

                object oDataPathValue;
                if (values.TryGetValue(ODataRouteConstants.ODataPath, out oDataPathValue))
                {
                    string oDataPath = oDataPathValue as string;
                    // Create request container
                    request.CreateRequestContainer(RouteName);

                    // Check whether the request is a POST targeted at a resource path ending in /$query
                    if (request.IsQueryRequest(oDataPath))
                    {
                        request.TransformQueryRequest();

                        oDataPath = oDataPath.Substring(0, oDataPath.LastIndexOf('/' + ODataRouteConstants.QuerySegment, StringComparison.OrdinalIgnoreCase));
                        values[ODataRouteConstants.ODataPath] = oDataPath;
                    }

                    string requestLeftPart = request.RequestUri.GetLeftPart(UriPartial.Path);
                    string queryString     = request.RequestUri.Query;

                    path = GetODataPath(oDataPath, requestLeftPart, queryString, () => request.GetRequestContainer());
                }

                if (path != null)
                {
                    // Set all the properties we need for routing, querying, formatting
                    HttpRequestMessageProperties properties = request.ODataProperties();
                    properties.Path      = path;
                    properties.RouteName = RouteName;

                    if (!values.ContainsKey(ODataRouteConstants.Controller))
                    {
                        // Select controller name using the routing conventions
                        string controllerName = SelectControllerName(path, request);
                        if (controllerName != null)
                        {
                            values[ODataRouteConstants.Controller] = controllerName;
                        }
                    }

                    return(true);
                }

                // The request doesn't match this route so dispose the request container.
                request.DeleteRequestContainer(true);
                return(false);
            }
            else
            {
                // This constraint only applies to URI resolution
                return(true);
            }
        }
Beispiel #26
0
        public virtual HttpActionDescriptor?SelectAction(HttpControllerContext controllerContext)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException(nameof(controllerContext));
            }

            if (!controllerContext.ControllerDescriptor.ControllerType.GetTypeInfo().IsDtoController())
            {
                return(_webApiControllerActionSelector.SelectAction(controllerContext));
            }

            if (!controllerContext.ControllerDescriptor.Properties.ContainsKey("CachedActionsList"))
            {
                GetActionMapping(controllerContext.ControllerDescriptor);
            }

            List <ReflectedHttpActionDescriptor> allActions = (List <ReflectedHttpActionDescriptor>)controllerContext.ControllerDescriptor.Properties["CachedActionsList"];

            HttpRequestMessageProperties props     = controllerContext.Request.ODataProperties();
            IDictionary <string, object> routeData = ((HttpRouteData)controllerContext.RouteData).Values;

            routeData.TryGetValue("action", out object?actionNameObj);

            string?actionName = props.Path.Segments.OfType <OperationSegment>().SelectMany(o => o.Operations).FirstOrDefault()?.Name ?? (actionNameObj == null ? controllerContext.Request.Method.Method : Convert.ToString(actionNameObj, CultureInfo.InvariantCulture));

            HttpActionDescriptor?resultAction = null;

            if (string.Equals(actionName, HttpMethod.Get.Method, StringComparison.InvariantCultureIgnoreCase) && controllerContext.Request.Method == HttpMethod.Get)
            {
                if (props.Path.Segments.OfType <KeySegment>().Any()) // get by key
                {
                    resultAction = allActions.ExtendedSingleOrDefault($"Finding Get by key action in {controllerContext.ControllerDescriptor.ControllerName} controller", action => action.MethodInfo.GetCustomAttribute <GetAttribute>() != null && action.MethodInfo.GetParameters().Any(p => p.Name == "key"));
                }
                else // get all
                {
                    resultAction = allActions.ExtendedSingleOrDefault($"Finding Get all action in {controllerContext.ControllerDescriptor.ControllerName} controller", action => action.MethodInfo.GetCustomAttribute <GetAttribute>() != null && action.MethodInfo.GetParameters().All(p => typeof(CancellationToken).IsAssignableFrom(p.ParameterType) || typeof(ODataQueryOptions).IsAssignableFrom(p.ParameterType)));
                }
            }
            else if (string.Equals(actionName, HttpMethod.Post.Method, StringComparison.InvariantCultureIgnoreCase) && controllerContext.Request.Method == HttpMethod.Post)
            {
                resultAction = allActions.ExtendedSingleOrDefault($"Finding create action in {controllerContext.ControllerDescriptor.ControllerName} controller", action => action.MethodInfo.GetCustomAttribute <CreateAttribute>() != null);
            }
            else if (string.Equals(actionName, HttpMethod.Put.Method, StringComparison.InvariantCultureIgnoreCase) && controllerContext.Request.Method == HttpMethod.Put)
            {
                resultAction = allActions.ExtendedSingleOrDefault($"Finding update action in {controllerContext.ControllerDescriptor.ControllerName} controller", action => action.MethodInfo.GetCustomAttribute <UpdateAttribute>() != null);
            }
            else if (string.Equals(actionName, "Patch", StringComparison.InvariantCultureIgnoreCase) && controllerContext.Request.Method == new HttpMethod("Patch"))
            {
                resultAction = allActions.ExtendedSingleOrDefault($"Finding partial update action in {controllerContext.ControllerDescriptor.ControllerName} controller", action => action.MethodInfo.GetCustomAttribute <PartialUpdateAttribute>() != null);
            }
            else if (string.Equals(actionName, HttpMethod.Delete.Method, StringComparison.InvariantCultureIgnoreCase) && controllerContext.Request.Method == HttpMethod.Delete)
            {
                resultAction = allActions.ExtendedSingleOrDefault($"Finding delete action in {controllerContext.ControllerDescriptor.ControllerName} controller", action => action.MethodInfo.GetCustomAttribute <DeleteAttribute>() != null);
            }
            else
            {
                resultAction = allActions.ExtendedSingleOrDefault($"Finding odata action/function for {actionName} in {controllerContext.ControllerDescriptor.ControllerName} controller", action => string.Equals(action.MethodInfo.Name, actionName, StringComparison.InvariantCultureIgnoreCase));
            }

            return(resultAction);
        }
        public override bool Match(
            HttpRequestMessage request,
            IHttpRoute route,
            string parameterName,
            IDictionary <string, object> values,
            HttpRouteDirection routeDirection)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            if (values == null)
            {
                throw new ArgumentNullException("values");
            }

            if (routeDirection != HttpRouteDirection.UriResolution)
            {
                return(true);
            }

            object oDataPathValue;

            if (!values.TryGetValue(ODataRouteConstants.ODataPath, out oDataPathValue))
            {
                return(false);
            }

            var service = RootStartup.Stack.GetServices().Find(request.RequestUri.PathAndQuery.Split('?')[0].Trim('/'));

            if (service == null || service.ResponseType == null || !service.ResponseType.IsGenericType || service.ResponseType.GetGenericTypeDefinition() != typeof(IQueryable <>))
            {
                return(false);
            }

            string oDataPathString = oDataPathValue as string;

            ODataPath path;
            IEdmModel model;

            try
            {
                request.Properties[Constants.CustomODataPath] = oDataPathString;


                model           = this.EdmModelProvider(request);
                oDataPathString = (string)request.Properties[Constants.CustomODataPath];

                string requestLeftPart = request.RequestUri.GetLeftPart(UriPartial.Path);
                string serviceRoot     = requestLeftPart;

                if (!String.IsNullOrEmpty(oDataPathString))
                {
                    serviceRoot = RemoveODataPath(serviceRoot, oDataPathString);
                }

                string oDataPathAndQuery = requestLeftPart.Substring(serviceRoot.Length);
                if (!String.IsNullOrEmpty(request.RequestUri.Query))
                {
                    oDataPathAndQuery += request.RequestUri.Query;
                }

                if (serviceRoot.EndsWith(_escapedSlash, StringComparison.OrdinalIgnoreCase))
                {
                    serviceRoot = serviceRoot.Substring(0, serviceRoot.Length - 3);
                }

                path = this.PathHandler.Parse(model, serviceRoot, ((Type)request.Properties[Constants.QueryType]).Name + "?" + request.RequestUri.Query);
            }
            catch (ODataException)
            {
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }

            if (path == null)
            {
                return(false);
            }

            HttpRequestMessageProperties odataProperties = request.ODataProperties();

            odataProperties.Model              = model;
            odataProperties.PathHandler        = this.PathHandler;
            odataProperties.Path               = path;
            odataProperties.RouteName          = this.RouteName;
            odataProperties.RoutingConventions = this.RoutingConventions;

            if (values.ContainsKey(ODataRouteConstants.Controller))
            {
                return(true);
            }

            string controllerName = this.SelectControllerName(path, request);

            if (controllerName != null)
            {
                values[ODataRouteConstants.Controller] = controllerName;
            }

            return(true);
        }
Beispiel #28
0
        public override bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary <string, object> values, HttpRouteDirection routeDirection)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (values == null)
            {
                throw new ArgumentNullException(nameof(values));
            }

            if (routeDirection != HttpRouteDirection.UriResolution)
            {
                return(true);
            }

            object oDataPathValue;

            if (!values.TryGetValue(ODataRouteConstants.ODataPath, out oDataPathValue))
            {
                return(false);
            }

            string oDataPathString = oDataPathValue as string;

            ODataPath path;
            IEdmModel model;

            try
            {
                model = EdmModelProvider(request);

                string requestLeftPart = request.RequestUri.GetLeftPart(UriPartial.Path);
                string serviceRoot     = requestLeftPart;

                if (!string.IsNullOrEmpty(oDataPathString))
                {
                    serviceRoot = RemoveODataPath(serviceRoot, oDataPathString);
                }

                string oDataPathAndQuery = requestLeftPart.Substring(serviceRoot.Length);
                oDataPathAndQuery = WebUtility.UrlDecode(oDataPathAndQuery);
                path = PathHandler.Parse(model, oDataPathAndQuery);
            }
            catch (Exception)
            {
                throw;
                //TODO: add logging
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }

            if (path == null)
            {
                return(false);
            }

            HttpRequestMessageProperties odataProperties = request.ODataProperties();

            odataProperties.Model              = model;
            odataProperties.PathHandler        = PathHandler;
            odataProperties.Path               = path;
            odataProperties.RouteName          = RouteName;
            odataProperties.RoutingConventions = RoutingConventions;
            values.Add(typeof(IDataService).FullName, _dataService);

            if (values.ContainsKey(ODataRouteConstants.Controller))
            {
                return(true);
            }

            string controllerName = SelectControllerName(path, request);

            if (controllerName != null)
            {
                values[ODataRouteConstants.Controller] = controllerName;
            }

            return(true);
        }