Пример #1
0
        /// <summary>
        /// Execute the query.
        /// </summary>
        /// <param name="responseValue">The response value.</param>
        /// <param name="singleResultCollection">The content as SingleResult.Queryable.</param>
        /// <param name="actionDescriptor">The action context, i.e. action and controller name.</param>
        /// <param name="modelFunction">A function to get the model.</param>
        /// <param name="request">The internal request.</param>
        /// <param name="createQueryOptionFunction">A function used to create and validate query options.</param>
        /// <returns></returns>
        private object ExecuteQuery(
            object responseValue,
            IQueryable singleResultCollection,
            IWebApiActionDescriptor actionDescriptor,
            Func <Type, IEdmModel> modelFunction,
            IWebApiRequestMessage request,
            Func <ODataQueryContext, IODataQueryOptions> createQueryOptionFunction)
        {
            ODataQueryContext queryContext = GetODataQueryContext(responseValue, singleResultCollection, actionDescriptor, modelFunction, request.Context.Path);

            // Create and validate the query options.
            IODataQueryOptions queryOptions = createQueryOptionFunction(queryContext);

            // apply the query
            IEnumerable enumerable = responseValue as IEnumerable;

            if (enumerable == null || responseValue is string || responseValue is byte[])
            {
                // response is not a collection; we only support $select and $expand on single entities.
                ValidateSelectExpandOnly(queryOptions);

                if (singleResultCollection == null)
                {
                    // response is a single entity.
                    return(ApplyQuery(entity: responseValue, queryOptions: queryOptions));
                }
                else
                {
                    IQueryable queryable = singleResultCollection as IQueryable;
                    queryable = ApplyQuery(queryable, queryOptions);
                    return(SingleOrDefault(queryable, actionDescriptor));
                }
            }
            else
            {
                // response is a collection.
                IQueryable queryable = (enumerable as IQueryable) ?? enumerable.AsQueryable();
                queryable = ApplyQuery(queryable, queryOptions);

                if (request.IsCountRequest())
                {
                    long?count = request.Context.TotalCount;

                    if (count.HasValue)
                    {
                        // Return the count value if it is a $count request.
                        return(count.Value);
                    }
                }

                return(queryable);
            }
        }
Пример #2
0
        private static ODataPayloadKind?GetEdmObjectPayloadKind(Type type, IWebApiRequestMessage internalRequest)
        {
            if (internalRequest.IsCountRequest())
            {
                return(ODataPayloadKind.Value);
            }

            Type elementType;

            if (TypeHelper.IsCollection(type, out elementType))
            {
                if (typeof(IEdmComplexObject).IsAssignableFrom(elementType) || typeof(IEdmEnumObject).IsAssignableFrom(elementType))
                {
                    return(ODataPayloadKind.Collection);
                }
                else if (typeof(IEdmEntityObject).IsAssignableFrom(elementType))
                {
                    return(ODataPayloadKind.ResourceSet);
                }
                else if (typeof(IEdmChangedObject).IsAssignableFrom(elementType))
                {
                    return(ODataPayloadKind.Delta);
                }
            }
            else
            {
                if (typeof(IEdmComplexObject).IsAssignableFrom(elementType) || typeof(IEdmEnumObject).IsAssignableFrom(elementType))
                {
                    return(ODataPayloadKind.Property);
                }
                else if (typeof(IEdmEntityObject).IsAssignableFrom(elementType))
                {
                    return(ODataPayloadKind.Resource);
                }
            }

            return(null);
        }
Пример #3
0
        /// <summary>
        /// Performs the query composition after action is executed. It first tries to retrieve the IQueryable from the
        /// returning response message. It then validates the query from uri based on the validation settings on
        /// <see cref="EnableQueryAttribute"/>. It finally applies the query appropriately, and reset it back on
        /// the response message.
        /// </summary>
        /// <param name="responseValue">The response content value.</param>
        /// <param name="singleResultCollection">The content as SingleResult.Queryable.</param>
        /// <param name="actionDescriptor">The action context, i.e. action and controller name.</param>
        /// <param name="request">The internal request.</param>
        /// <param name="modelFunction">A function to get the model.</param>
        /// <param name="createQueryOptionFunction">A function used to create and validate query options.</param>
        /// <param name="createResponseAction">An action used to create a response.</param>
        /// <param name="createErrorAction">A function used to generate error response.</param>
        private object OnActionExecuted(
            object responseValue,
            IQueryable singleResultCollection,
            IWebApiActionDescriptor actionDescriptor,
            IWebApiRequestMessage request,
            Func <Type, IEdmModel> modelFunction,
            Func <ODataQueryContext, IODataQueryOptions> createQueryOptionFunction,
            Action <HttpStatusCode> createResponseAction,
            Action <HttpStatusCode, string, Exception> createErrorAction)
        {
            if (!_querySettings.PageSize.HasValue && responseValue != null)
            {
                GetModelBoundPageSize(responseValue, singleResultCollection, actionDescriptor, modelFunction, request.Context.Path, createErrorAction);
            }

            // Apply the query if there are any query options, if there is a page size set, in the case of
            // SingleResult or in the case of $count request.
            bool shouldApplyQuery = responseValue != null &&
                                    request.RequestUri != null &&
                                    (!String.IsNullOrWhiteSpace(request.RequestUri.Query) ||
                                     _querySettings.PageSize.HasValue ||
                                     _querySettings.ModelBoundPageSize.HasValue ||
                                     singleResultCollection != null ||
                                     request.IsCountRequest() ||
                                     ContainsAutoSelectExpandProperty(responseValue, singleResultCollection, actionDescriptor, modelFunction, request.Context.Path));

            object returnValue = null;

            if (shouldApplyQuery)
            {
                try
                {
                    object queryResult = ExecuteQuery(responseValue, singleResultCollection, actionDescriptor, modelFunction, request, createQueryOptionFunction);
                    if (queryResult == null && (request.Context.Path == null || singleResultCollection != null))
                    {
                        // This is the case in which a regular OData service uses the EnableQuery attribute.
                        // For OData services ODataNullValueMessageHandler should be plugged in for the service
                        // if this behavior is desired.
                        // For non OData services this behavior is equivalent as the one in the v3 version in order
                        // to reduce the friction when they decide to move to use the v4 EnableQueryAttribute.
                        createResponseAction(HttpStatusCode.NotFound);
                    }

                    returnValue = queryResult;
                }
                catch (ArgumentOutOfRangeException e)
                {
                    createErrorAction(
                        HttpStatusCode.BadRequest,
                        Error.Format(SRResources.QueryParameterNotSupported, e.Message),
                        e);
                }
                catch (NotImplementedException e)
                {
                    createErrorAction(
                        HttpStatusCode.BadRequest,
                        Error.Format(SRResources.UriQueryStringInvalid, e.Message),
                        e);
                }
                catch (NotSupportedException e)
                {
                    createErrorAction(
                        HttpStatusCode.BadRequest,
                        Error.Format(SRResources.UriQueryStringInvalid, e.Message),
                        e);
                }
                catch (InvalidOperationException e)
                {
                    // Will also catch ODataException here because ODataException derives from InvalidOperationException.
                    createErrorAction(
                        HttpStatusCode.BadRequest,
                        Error.Format(SRResources.UriQueryStringInvalid, e.Message),
                        e);
                }
            }

            return(returnValue);
        }