Exemple #1
0
        public void BuildQuery_ReturnsNull_IfPathHasUnsupportedSegmen(string path)
        {
            var                  model        = ODataPathQueryModel.GetModel();
            var                  pathHandler  = new DefaultODataPathHandler();
            var                  odataPath    = pathHandler.Parse(model, "http://any/", path);
            IQueryable           source       = Array.CreateInstance(typeof(ODataPathQuery_Customer), 0).AsQueryable();
            var                  queryBuilder = new ODataPathQueryBuilder(source, odataPath);
            ODataPathQueryResult result       = queryBuilder.BuildQuery();

            Assert.Null(result);
        }
Exemple #2
0
        public void BuildQuery_SetValueFlagToTrue_IfPathHasValueSegment(string path, string expectedQuery)
        {
            var                  model        = ODataPathQueryModel.GetModel();
            var                  pathHandler  = new DefaultODataPathHandler();
            var                  odataPath    = pathHandler.Parse(model, "http://any/", path);
            IQueryable           source       = Array.CreateInstance(typeof(ODataPathQuery_Customer), 0).AsQueryable();
            var                  queryBuilder = new ODataPathQueryBuilder(source, odataPath);
            ODataPathQueryResult result       = queryBuilder.BuildQuery();

            string queryExpression = ExpressionStringBuilder.ToString(result.Result.Expression);

            queryExpression = RemoveNameSpace(queryExpression);

            Assert.Equal(expectedQuery, queryExpression);
            Assert.True(result.HasValueSegment);
            Assert.False(result.HasCountSegment);
        }
        /// <summary>
        /// Transforms the result of the action based on the sequence of property accesses in the odata path
        /// after the action is executed.
        /// It first tries to retrieve the IQueryable from the
        /// returning response message. It then uses the <see cref="ODataPathQueryBuilder"/> to transform
        /// the query and sets the result back to the response message.
        /// </summary>
        /// <param name="actionExecutedContext">The context related to this action, including the response message,
        /// request message and HttpConfiguration etc.</param>
        public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
        {
            if (actionExecutedContext == null)
            {
                throw Error.ArgumentNull("actionExecutedContext");
            }

            HttpRequest request = actionExecutedContext.HttpContext.Request;

            if (request == null)
            {
                throw Error.Argument("actionExecutedContext", SRResources.ActionExecutedContextMustHaveRequest);
            }

            ControllerActionDescriptor actionDescriptor = actionExecutedContext.ActionDescriptor as ControllerActionDescriptor;

            if (actionDescriptor == null)
            {
                throw Error.Argument("actionExecutedContext", SRResources.ActionContextMustHaveDescriptor);
            }

            HttpResponse response = actionExecutedContext.HttpContext.Response;

            ObjectResult responseContent = actionExecutedContext.Result as ObjectResult;
            IQueryable   result          = responseContent.Value as IQueryable;
            SingleResult singleResult    = responseContent.Value as SingleResult;

            if (singleResult != null)
            {
                // This could be a SingleResult, which has the property Queryable.
                // But it could be a SingleResult() or SingleResult<T>. Sort by number of parameters
                // on the property and get the one with the most parameters.
                PropertyInfo propInfo = singleResult.GetType().GetProperties()
                                        .Where(p => p.Name.Equals("Queryable"))
                                        .OrderByDescending(p => p.GetIndexParameters().Count())
                                        .FirstOrDefault();

                result = propInfo.GetValue(singleResult) as IQueryable;
            }

            if (result != null)
            {
                ODataPath path  = actionExecutedContext.HttpContext.ODataFeature().Path;
                IEdmModel model = actionExecutedContext.HttpContext.Request.GetModel();

                var queryBuilder = new ODataPathQueryBuilder(result, path);
                ODataPathQueryResult transformedResult = queryBuilder.BuildQuery();

                if (transformedResult == null)
                {
                    actionExecutedContext.Result = new NotFoundObjectResult(null);
                }
                else if (path.EdmType.TypeKind == EdmTypeKind.Collection || transformedResult.HasCountSegment)
                {
                    responseContent.Value = transformedResult.Result;
                }
                else
                {
                    Type elementType = transformedResult.Result.ElementType;

                    // If we return the IQueryable as the result, then the response will be returned as a collection
                    // so we have to return a single result. We can either return the materialized single result using SingleOrDefault,
                    // which will run the query against the underlying data source. Or we can wrap the IQueryable result with
                    // a SingleResult<T>.
                    // If the action has [EnableQuery], then we return a SingleResult<T> which allows query options to be
                    // applied to the IQueryable. If we returned the materialized object, then query options like $expand
                    // would return null because navigation properties are not fetched from relational databases by default.
                    // If the action does not have [EnableQuery], then we run the query using SingleOrDefault and return the
                    // actual object. If we returned a SingleResult<T> in this case, we'd get an error because the serializer
                    // does not recognize it.
                    if (actionDescriptor.MethodInfo.GetCustomAttributes <EnableQueryAttribute>().Any())
                    {
                        // calls SingleResult.Create<T>(IQueryable<T>)
                        responseContent.Value = ExpressionHelpers.CreateSingleResult(transformedResult.Result, transformedResult.Result.ElementType);
                    }
                    else
                    {
                        try
                        {
                            object singleValue = QueryHelpers.SingleOrDefault(transformedResult.Result, new WebApiActionDescriptor(actionDescriptor));

                            if (singleValue == null)
                            {
                                actionExecutedContext.Result = new NotFoundObjectResult(null);
                            }
                            else
                            {
                                responseContent.Value = singleValue;
                            }
                        }
                        catch (NullReferenceException)
                        {
                            actionExecutedContext.Result = new NotFoundObjectResult(null);
                        }
                    }
                }
            }
        }