/// <summary>
        /// Validates a <see cref="TopQueryOption" />.
        /// </summary>
        /// <param name="selectExpandQueryOption">The $select and $expand query.</param>
        /// <param name="validationSettings">The validation settings.</param>
        public virtual void Validate(SelectExpandQueryOption selectExpandQueryOption, ODataValidationSettings validationSettings)
        {
            if (selectExpandQueryOption == null)
            {
                throw Error.ArgumentNull("selectExpandQueryOption");
            }

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

            IEdmModel model = selectExpandQueryOption.Context.Model;
            ValidateRestrictions(selectExpandQueryOption.SelectExpandClause, model);

            if (validationSettings.MaxExpansionDepth > 0)
            {
                if (selectExpandQueryOption.LevelsMaxLiteralExpansionDepth > validationSettings.MaxExpansionDepth)
                {
                    throw new ODataException(Error.Format(
                        SRResources.InvalidExpansionDepthValue,
                        "LevelsMaxLiteralExpansionDepth",
                        "MaxExpansionDepth"));
                }

                ValidateDepth(selectExpandQueryOption.SelectExpandClause, validationSettings.MaxExpansionDepth);
            }
        }
        public virtual void Validate(OrderByQueryOption orderByOption, ODataValidationSettings validationSettings)
        {
            if (orderByOption == null)
            {
                throw Error.ArgumentNull("orderByOption");
            }

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

            if (validationSettings.AllowedOrderByProperties.Count > 0)
            {
                ICollection<OrderByPropertyNode> propertyNodes = orderByOption.PropertyNodes;

                foreach (OrderByPropertyNode property in propertyNodes)
                {
                    if (!validationSettings.AllowedOrderByProperties.Contains(property.Property.Name))
                    {
                        throw new ODataException(Error.Format(SRResources.NotAllowedOrderByProperty, property.Property.Name, "AllowedOrderByProperties"));
                    }
                }
            }
        }
        /// <summary>
        /// Override this method to restrict the 'all' query inside the filter query.
        /// </summary>
        /// <remarks>
        /// This method is intended to be called from method overrides in subclasses. This method also supports unit-testing scenarios and is not intended to be called from user code.
        /// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance.
        /// </remarks>
        /// <param name="allNode"></param>
        /// <param name="settings"></param>
        public virtual void ValidateAllNode(AllNode allNode, ODataValidationSettings settings)
        {
            if (allNode == null)
            {
                throw Error.ArgumentNull("allNode");
            }

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

            EnterLambda(settings);

            try
            {
                ValidateQueryNode(allNode.Source, settings);

                ValidateQueryNode(allNode.Body, settings);
            }
            finally
            {
                ExitLambda();
            }
        }
        /// <summary>
        /// Validates a <see cref="CountQueryOption" />.
        /// </summary>
        /// <param name="countQueryOption">The $count query.</param>
        /// <param name="validationSettings">The validation settings.</param>
        public virtual void Validate(CountQueryOption countQueryOption, ODataValidationSettings validationSettings)
        {
            if (countQueryOption == null)
            {
                throw Error.ArgumentNull("countQueryOption");
            }

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

            ODataPath path = countQueryOption.Context.Path;

            if (path != null && path.Segments.Count > 0)
            {
                ODataPathSegment lastSegment = path.Segments.Last();

                if (lastSegment is CountPathSegment && path.Segments.Count > 1)
                {
                    ValidateCount(path.Segments[path.Segments.Count - 2], countQueryOption.Context.Model);
                }
                else
                {
                    ValidateCount(lastSegment, countQueryOption.Context.Model);
                }
            }
        }
        /// <summary>
        /// Validates the specified query options.
        /// </summary>
        /// <param name="queryOptions">The query options.</param>
        /// <param name="validationSettings">The validation settings.</param>
        /// <exception cref="ODataException">Thrown if the validation fails.</exception>
        internal static void Validate(ODataQueryOptions queryOptions, ODataValidationSettings validationSettings)
        {
            if (queryOptions.Filter != null)
            {
                if ((validationSettings.AllowedQueryOptions & AllowedQueryOptions.Filter) != AllowedQueryOptions.Filter)
                {
                    throw new ODataException(Messages.FilterQueryOptionNotSupported);
                }

                ValidateFunctions(queryOptions.Filter.RawValue, validationSettings);
                ValidateStringFunctions(queryOptions.Filter.RawValue, validationSettings);
                ValidateDateFunctions(queryOptions.Filter.RawValue, validationSettings);
                ValidateMathFunctions(queryOptions.Filter.RawValue, validationSettings);
                ValidateLogicalOperators(queryOptions.Filter.RawValue, validationSettings);
                ValidateArithmeticOperators(queryOptions.Filter.RawValue, validationSettings);
            }

            if (queryOptions.RawValues.Expand != null
                && (validationSettings.AllowedQueryOptions & AllowedQueryOptions.Expand) != AllowedQueryOptions.Expand)
            {
                throw new ODataException(Messages.ExpandQueryOptionNotSupported);
            }

            if (queryOptions.RawValues.Format != null
                && (validationSettings.AllowedQueryOptions & AllowedQueryOptions.Format) != AllowedQueryOptions.Format)
            {
                throw new ODataException(Messages.FormatQueryOptionNotSupported);
            }

            if (queryOptions.RawValues.InlineCount != null
                && (validationSettings.AllowedQueryOptions & AllowedQueryOptions.InlineCount) != AllowedQueryOptions.InlineCount)
            {
                throw new ODataException(Messages.InlineCountQueryOptionNotSupported);
            }

            if (queryOptions.RawValues.OrderBy != null
                && (validationSettings.AllowedQueryOptions & AllowedQueryOptions.OrderBy) != AllowedQueryOptions.OrderBy)
            {
                throw new ODataException(Messages.OrderByQueryOptionNotSupported);
            }

            if (queryOptions.RawValues.Select != null
                && (validationSettings.AllowedQueryOptions & AllowedQueryOptions.Select) != AllowedQueryOptions.Select)
            {
                throw new ODataException(Messages.SelectQueryOptionNotSupported);
            }

            if (queryOptions.RawValues.Skip != null
                && (validationSettings.AllowedQueryOptions & AllowedQueryOptions.Skip) != AllowedQueryOptions.Skip)
            {
                throw new ODataException(Messages.SkipQueryOptionNotSupported);
            }

            if (queryOptions.RawValues.Top != null
                && (validationSettings.AllowedQueryOptions & AllowedQueryOptions.Top) != AllowedQueryOptions.Top)
            {
                throw new ODataException(Messages.TopQueryOptionNotSupported);
            }
        }
        public void Validate_NoException_ForAllowedAndSortableUnlimitedProperty_OnEmptyAllowedPropertiesList()
        {
            // Arrange: empty allowed orderby list
            ODataValidationSettings settings = new ODataValidationSettings();

            // Act & Assert
            Assert.DoesNotThrow(() => _validator.Validate(new OrderByQueryOption("Name asc", _context), settings));
        }
        public void ValidateAllowsOrderByIt()
        {
            // Arrange
            OrderByQueryOption option = new OrderByQueryOption("$it", _context);
            ODataValidationSettings settings = new ODataValidationSettings();

            // Act & Assert
            Assert.DoesNotThrow(() => _validator.Validate(option, settings));
        }
        public void ValidatePassWhenLimitIsNotReached()
        {
            ODataValidationSettings settings = new ODataValidationSettings()
            {
                MaxSkip = 10
            };

            Assert.DoesNotThrow(() => _validator.Validate(new SkipQueryOption("9", _context), settings));
        }
        public void Validate_DoesntThrowNotSortableException_ForNotSortableProperty_OnNonEmptyAllowedPropertiesList(string property)
        {
            // Arrange : nonempty allowed orderby list
            ODataValidationSettings settings = new ODataValidationSettings();
            settings.AllowedOrderByProperties.Add(property);

            // Act & Assert
            _validator.Validate(new OrderByQueryOption(String.Format("{0} asc", property), _context), settings);
        }
        public void Validate_DoesntThrowUnsortableException_ForUnsortableProperty_OnNonEmptyAllowedPropertiesList()
        {
            // Arrange : nonempty allowed orderby list
            ODataValidationSettings settings = new ODataValidationSettings();
            settings.AllowedOrderByProperties.Add("UnsortableProperty");

            // Act & Assert
            _validator.Validate(new OrderByQueryOption("UnsortableProperty asc", _context), settings);
        }
 public FilterQueryValidatorTest()
 {
     _validator = new MyFilterValidator();
     _builder = new ODataConventionModelBuilder();
     _builder.EntitySet<QueryCompositionCustomer>("Customer");
     _model = _builder.GetEdmModel();
     _settings = new ODataValidationSettings();
     _context = new ODataQueryContext(_model, typeof(QueryCompositionCustomer));
 }
        public void ValidateThrowsOnUnsortable()
        {
            ODataValidationSettings settings = new ODataValidationSettings();
            settings.AllowedOrderByProperties.Add("UnsortableProperty");

            Assert.Throws<ODataException>(() =>
                _validator.Validate(new OrderByQueryOption("UnsortableProperty asc", _context), settings),
                "The property 'UnsortableProperty' cannot be used in the $orderby query option.");
        }
        public void ValidatePassWhenLimitIsNotReached()
        {
            ODataValidationSettings settings = new ODataValidationSettings()
            {
                MaxTop = 10
            };

            _validator.Validate(new TopQueryOption("9", _context), settings);
        }
 public void ValidatePassWhenLimitIsReached()
 {
     ODataValidationSettings settings = new ODataValidationSettings()
     {
         MaxSkip = 10
     };
     
     _validator.Validate(new SkipQueryOption("10", _context), settings);
 }
        public void Validate_ThrowsUnsortableException_ForUnsortableProperty_OnEmptyAllowedPropertiesList()
        {
            // Arrange : empty allowed orderby list
            ODataValidationSettings settings = new ODataValidationSettings();

            // Act & Assert
            Assert.Throws<ODataException>(() => _validator.Validate(new OrderByQueryOption("UnsortableProperty asc", _context), settings),
                "The property 'UnsortableProperty' cannot be used in the $orderby query option.");
        }
        public void ValidateAllowsOrderByIt()
        {
            // Arrange
            OrderByQueryOption option = new OrderByQueryOption("$it", new ODataQueryContext(EdmCoreModel.Instance, typeof(int)));
            ODataValidationSettings settings = new ODataValidationSettings();

            // Act & Assert
            Assert.DoesNotThrow(() => _validator.Validate(option, settings));
        }
        public void ValidateAllowsOrderByIt_IfExplicitlySpecified()
        {
            // Arrange
            OrderByQueryOption option = new OrderByQueryOption("$it", new ODataQueryContext(EdmCoreModel.Instance, typeof(int)), queryTranslator: null);
            ODataValidationSettings settings = new ODataValidationSettings { AllowedOrderByProperties = { "$it" } };

            // Act & Assert
            Assert.DoesNotThrow(() => _validator.Validate(option, settings));
        }
        public void Validate_ThrowsNotAllowedException_ForNotAllowedAndSortableLimitedProperty()
        {
            // Arrange
            ODataValidationSettings settings = new ODataValidationSettings();
            settings.AllowedOrderByProperties.Add("Name");

            // Act & Assert
            Assert.Throws<ODataException>(() => _validator.Validate(new OrderByQueryOption("UnsortableProperty asc", _context), settings),
                "Order by 'UnsortableProperty' is not allowed. To allow it, set the 'AllowedOrderByProperties' property on EnableQueryAttribute or QueryValidationSettings.");
        }
        public void ValidateThrowsWhenLimitIsExceeded()
        {
            ODataValidationSettings settings = new ODataValidationSettings()
            {
                MaxSkip = 10
            };

            Assert.Throws<ODataException>(() =>
                _validator.Validate(new SkipQueryOption("11", _context), settings));
        }
        public void ValidateWillAllowId()
        {
            // Arrange
            OrderByQueryOption option = new OrderByQueryOption("Id", _context);
            ODataValidationSettings settings = new ODataValidationSettings();
            settings.AllowedOrderByProperties.Add("Id");

            // Act & Assert
            Assert.DoesNotThrow(() => _validator.Validate(option, settings));
        }
        public void ValidateThrowsWhenLimitIsExceeded()
        {
            ODataValidationSettings settings = new ODataValidationSettings()
            {
                MaxSkip = 10
            };

            Assert.Throws<ODataException>(() =>
                _validator.Validate(new SkipQueryOption("11", _context), settings),
                "The limit of '10' for Skip query has been exceeded. The value from the incoming request is '11'.");
        }
        public void ValidateWillNotAllowName()
        {
            // Arrange
            OrderByQueryOption option = new OrderByQueryOption("Name", _context);
            ODataValidationSettings settings = new ODataValidationSettings();
            settings.AllowedOrderByProperties.Add("Id");

            // Act & Assert
            Assert.Throws<ODataException>(() => _validator.Validate(option, settings),
                "Order by 'Name' is not allowed. To allow it, set the 'AllowedOrderByProperties' property on QueryableAttribute or QueryValidationSettings.");
        }
        public void Validate_ThrowsNotSortableException_ForNotSortableProperty_OnEmptyAllowedPropertiesList(string property)
        {
            // Arrange : empty allowed orderby list
            ODataValidationSettings settings = new ODataValidationSettings();

            // Act & Assert
            Assert.Throws<ODataException>(() =>
                _validator.Validate(
                    new OrderByQueryOption(String.Format("{0} asc", property), _context), settings),
                String.Format("The property '{0}' cannot be used in the $orderby query option.", property));
        }
        public void ValidateDisallowsOrderByIt_IfTurnedOff()
        {
            // Arrange
            _context = new ODataQueryContext(EdmCoreModel.Instance, typeof(int));
            OrderByQueryOption option = new OrderByQueryOption("$it", _context, queryTranslator: null);
            ODataValidationSettings settings = new ODataValidationSettings();
            settings.AllowedOrderByProperties.Add("dummy");

            // Act & Assert
            Assert.Throws<ODataException>(
                () => _validator.Validate(option, settings),
                "Order by '$it' is not allowed. To allow it, set the 'AllowedOrderByProperties' property on EnableQueryAttribute or QueryValidationSettings.");
        }
        /// <summary>
        /// The entry point of this validator class. Use this method to validate the FilterQueryOption
        /// </summary>
        public virtual void Validate(FilterQueryOption filterQueryOption, ODataValidationSettings settings)
        {
            if (filterQueryOption == null)
            {
                throw Error.ArgumentNull("filterQueryOption");
            }

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

            ValidateQueryNode(filterQueryOption.FilterClause.Expression, settings);
        }
        public void ValidateWillNotAllowMultipleProperties()
        {
            // Arrange
            OrderByQueryOption option = new OrderByQueryOption("Name desc, Id asc", _context);
            ODataValidationSettings settings = new ODataValidationSettings();
            Assert.DoesNotThrow(() => _validator.Validate(option, settings));

            settings.AllowedOrderByProperties.Add("Address");
            settings.AllowedOrderByProperties.Add("Name");

            // Act & Assert
            Assert.Throws<ODataException>(() => _validator.Validate(option, settings),
                "Order by 'Id' is not allowed. To allow it, set the 'AllowedOrderByProperties' property on QueryableAttribute or QueryValidationSettings.");
        }
        public void ValidateAllowOrderBy()
        {
            // Arrange
            HttpRequestMessage message = new HttpRequestMessage(
                HttpMethod.Get,
                new Uri("http://localhost/?$orderby=Name")
            );
            ODataQueryOptions option = new ODataQueryOptions(_context, message);
            ODataValidationSettings settings = new ODataValidationSettings()
            {
                AllowedQueryOptions = AllowedQueryOptions.OrderBy
            };

            // Act & Assert
            Assert.DoesNotThrow(() => _validator.Validate(option, settings));
        }
        /// <summary>
        /// Override this method to restrict the 'all' query inside the filter query
        /// </summary>
        /// <param name="allNode"></param>
        /// <param name="settings"></param>
        public virtual void ValidateAllNode(AllNode allNode, ODataValidationSettings settings)
        {
            if (allNode == null)
            {
                throw Error.ArgumentNull("allNode");
            }

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

            ValidateQueryNode(allNode.Source, settings);

            ValidateQueryNode(allNode.Body, settings);
        }
        public void Validate_Throws_DollarCountAppliedOnNotCountableCollection(string uri, string message)
        {
            // Arrange
            IEdmModel model = GetEdmModel();
            var pathHandler = new DefaultODataPathHandler();
            string serviceRoot = "http://localhost/";
            ODataPath path = pathHandler.Parse(model, serviceRoot, uri);
            var context = new ODataQueryContext(
                model,
                EdmCoreModel.Instance.GetInt32(false).Definition,
                path);
            var option = new CountQueryOption("true", context);
            var settings = new ODataValidationSettings();

            // Act & Assert
            Assert.Throws<InvalidOperationException>(() => _validator.Validate(option, settings), message);
        }
        /// <summary>
        /// Validates a <see cref="SkipQueryOption" />.
        /// </summary>
        /// <param name="skipQueryOption">The $skip query.</param>
        /// <param name="validationSettings">The validation settings.</param>
        public virtual void Validate(SkipQueryOption skipQueryOption, ODataValidationSettings validationSettings)
        {
            if (skipQueryOption == null)
            {
                throw Error.ArgumentNull("skipQueryOption");
            }

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

            if (skipQueryOption.Value > validationSettings.MaxSkip)
            {
                throw new ODataException(Error.Format(SRResources.SkipTopLimitExceeded, validationSettings.MaxSkip, AllowedQueryOptions.Skip, skipQueryOption.Value));
            }
        }
Beispiel #31
0
        public async Task <HttpResponseMessage> Get(ODataQueryOptions <Watch> options)
        {
            var validationSettings = new ODataValidationSettings
            {
                MaxTop = 100,
                AllowedArithmeticOperators = AllowedArithmeticOperators.None,
                AllowedFunctions           = AllowedFunctions.None,
                AllowedLogicalOperators    =
                    AllowedLogicalOperators.Equal | AllowedLogicalOperators.And | AllowedLogicalOperators.GreaterThan | AllowedLogicalOperators.GreaterThanOrEqual | AllowedLogicalOperators.LessThan |
                    AllowedLogicalOperators.LessThanOrEqual,
                AllowedQueryOptions = AllowedQueryOptions.Filter | AllowedQueryOptions.OrderBy |
                                      AllowedQueryOptions.Skip | AllowedQueryOptions.Top | AllowedQueryOptions.InlineCount
            };

            validationSettings.AllowedOrderByProperties.Add("Name");
            validationSettings.AllowedOrderByProperties.Add("Created");
            validationSettings.AllowedOrderByProperties.Add("HitsCount");


            // Validating OData
            try
            {
                options.Validate(validationSettings);
            }
            catch (Exception)
            {
                throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ResponseMessages.InvalidQueryOptions));
            }


            // Parsing filter parameters
            DataQueryOptions filter;

            try
            {
                filter = _mapper.Map <ODataQueryOptions, DataQueryOptions>(options);
            }
            catch (AutoMapperMappingException)
            {
                throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ResponseMessages.InvalidQueryOptions));
            }


            // Special instructions for UserId filtering
            DataFilterRule userIdFilter = filter.Filters.FirstOrDefault(f => string.Compare(f.Name, NameOfHelper.PropertyName <Watch>(x => x.UserId),
                                                                                            StringComparison.OrdinalIgnoreCase) == 0 && f.Type == DataFilterTypes.Equal);

            if (userIdFilter == null || userIdFilter.Value == null)
            {
                // For backward compatibility we treats not specified or empty UserId as current user
                if (string.IsNullOrEmpty(UserId))
                {
                    throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.Unauthorized, ResponseMessages.UnathorizedRequest));
                }

                if (userIdFilter == null)
                {
                    userIdFilter = new DataFilterRule {
                        Name = NameOfHelper.PropertyName <Watch>(x => x.UserId), Type = DataFilterTypes.Equal, Value = UserId
                    };
                    filter.Filters.Add(userIdFilter);
                }
                else
                {
                    userIdFilter.Value = UserId;
                }
            }
            else if (string.Compare(userIdFilter.Value.ToString(), UserIdAllConstant, StringComparison.OrdinalIgnoreCase) == 0)
            {
                // special constant $all means not filtering by UserId
                userIdFilter.Value = null;
            }


            // Retrieving projects
            DataResult <Watch> watchProjects;

            try
            {
                watchProjects = await _watchProjectRepository.GetSequenceAsync(filter, UserId);
            }
            catch (NotSupportedException)
            {
                throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ResponseMessages.BadRequest));
            }

            if (filter.Count)
            {
                var pageResult = new PageResult <Watch>(watchProjects.Results, null, watchProjects.Count);
                return(Request.CreateResponse(HttpStatusCode.OK, pageResult));
            }

            return(Request.CreateResponse(HttpStatusCode.OK, watchProjects.Results));
        }
Beispiel #32
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ODataValidationSettingsConvention"/> class.
 /// </summary>
 /// <param name="validationSettings">The <see cref="ODataValidationSettings">validation settings</see> the convention is based on.</param>
 /// <param name="settings">The <see cref="ODataQueryOptionSettings">settings</see> used by the convention.</param>
 public ODataValidationSettingsConvention(ODataValidationSettings validationSettings, ODataQueryOptionSettings settings)
 {
     ValidationSettings = validationSettings;
     Settings           = settings;
 }
Beispiel #33
0
        /// <summary>
        /// Validates the OData query.
        /// </summary>
        /// <param name="options">The OData query to validate.</param>
        /// <param name="validationSettings">The validation settings.</param>
        public virtual void Validate(ODataQueryOptions options, ODataValidationSettings validationSettings)
        {
            if (options == null)
            {
                throw Error.ArgumentNull("options");
            }

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

            // Validate each query options
            if (options.Skip != null)
            {
                ValidateQueryOptionAllowed(AllowedQueryOptions.Skip, validationSettings.AllowedQueryOptions);
                options.Skip.Validate(validationSettings);
            }

            if (options.Top != null)
            {
                ValidateQueryOptionAllowed(AllowedQueryOptions.Top, validationSettings.AllowedQueryOptions);
                options.Top.Validate(validationSettings);
            }

            if (options.OrderBy != null)
            {
                ValidateQueryOptionAllowed(AllowedQueryOptions.OrderBy, validationSettings.AllowedQueryOptions);
                options.OrderBy.Validate(validationSettings);
            }

            if (options.Filter != null)
            {
                ValidateQueryOptionAllowed(AllowedQueryOptions.Filter, validationSettings.AllowedQueryOptions);
                options.Filter.Validate(validationSettings);
            }

            if (options.Count != null || ODataCountMediaTypeMapping.IsCountRequest(options.Request))
            {
                ValidateQueryOptionAllowed(AllowedQueryOptions.Count, validationSettings.AllowedQueryOptions);

                if (options.Count != null)
                {
                    options.Count.Validate(validationSettings);
                }
            }

            if (options.RawValues.Expand != null)
            {
                ValidateQueryOptionAllowed(AllowedQueryOptions.Expand, validationSettings.AllowedQueryOptions);
            }

            if (options.RawValues.Select != null)
            {
                ValidateQueryOptionAllowed(AllowedQueryOptions.Select, validationSettings.AllowedQueryOptions);
            }

            if (options.SelectExpand != null)
            {
                options.SelectExpand.Validate(validationSettings);
            }

            if (options.RawValues.Format != null)
            {
                ValidateQueryOptionAllowed(AllowedQueryOptions.Format, validationSettings.AllowedQueryOptions);
            }

            if (options.RawValues.SkipToken != null)
            {
                ValidateQueryOptionAllowed(AllowedQueryOptions.SkipToken, validationSettings.AllowedQueryOptions);
            }

            if (options.RawValues.DeltaToken != null)
            {
                ValidateQueryOptionAllowed(AllowedQueryOptions.DeltaToken, validationSettings.AllowedQueryOptions);
            }
        }
        /// <summary>
        /// Override this method if you want to validate casts on single entities.
        /// </summary>
        /// <remarks>
        /// This method is intended to be called from method overrides in subclasses. This method also supports unit-testing scenarios and is not intended to be called from user code.
        /// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance.
        /// </remarks>
        /// <param name="singleEntityCastNode"></param>
        /// <param name="settings"></param>
        public virtual void ValidateSingleEntityCastNode(SingleEntityCastNode singleEntityCastNode, ODataValidationSettings settings)
        {
            if (singleEntityCastNode == null)
            {
                throw Error.ArgumentNull("singleEntityCastNode");
            }

            ValidateQueryNode(singleEntityCastNode.Source, settings);
        }
Beispiel #35
0
        protected virtual ODataValidationSettings OnCreateODataValidationSettings()
        {
            var oDataValidationSettings = new ODataValidationSettings();

            return(oDataValidationSettings);
        }
        private static void ValidateLogicalOperators(ODataQueryOptions queryOptions, ODataValidationSettings validationSettings)
        {
            if (validationSettings.AllowedLogicalOperators == AllowedLogicalOperators.All)
            {
                return;
            }

            string rawFilterValue = queryOptions.RawValues.Filter;

            if ((validationSettings.AllowedLogicalOperators & AllowedLogicalOperators.And) != AllowedLogicalOperators.And &&
                rawFilterValue.Contains(" and "))
            {
                throw ODataException.NotImplemented("Unsupported operator and", "$filter");
            }

            if ((validationSettings.AllowedLogicalOperators & AllowedLogicalOperators.Or) != AllowedLogicalOperators.Or &&
                rawFilterValue.Contains(" or "))
            {
                throw ODataException.NotImplemented("Unsupported operator or", "$filter");
            }

            if ((validationSettings.AllowedLogicalOperators & AllowedLogicalOperators.Equal) != AllowedLogicalOperators.Equal &&
                rawFilterValue.Contains(" eq "))
            {
                throw ODataException.NotImplemented("Unsupported operator eq", "$filter");
            }

            if ((validationSettings.AllowedLogicalOperators & AllowedLogicalOperators.NotEqual) != AllowedLogicalOperators.NotEqual &&
                rawFilterValue.Contains(" ne "))
            {
                throw ODataException.NotImplemented("Unsupported operator ne", "$filter");
            }

            if ((validationSettings.AllowedLogicalOperators & AllowedLogicalOperators.GreaterThan) != AllowedLogicalOperators.GreaterThan &&
                rawFilterValue.Contains(" gt "))
            {
                throw ODataException.NotImplemented("Unsupported operator gt", "$filter");
            }

            if ((validationSettings.AllowedLogicalOperators & AllowedLogicalOperators.GreaterThanOrEqual) != AllowedLogicalOperators.GreaterThanOrEqual &&
                rawFilterValue.Contains(" ge "))
            {
                throw ODataException.NotImplemented("Unsupported operator ge", "$filter");
            }

            if ((validationSettings.AllowedLogicalOperators & AllowedLogicalOperators.LessThan) != AllowedLogicalOperators.LessThan &&
                rawFilterValue.Contains(" lt "))
            {
                throw ODataException.NotImplemented("Unsupported operator lt", "$filter");
            }

            if ((validationSettings.AllowedLogicalOperators & AllowedLogicalOperators.LessThanOrEqual) != AllowedLogicalOperators.LessThanOrEqual &&
                rawFilterValue.Contains(" le "))
            {
                throw ODataException.NotImplemented("Unsupported operator le", "$filter");
            }

            if ((validationSettings.AllowedLogicalOperators & AllowedLogicalOperators.Has) != AllowedLogicalOperators.Has &&
                rawFilterValue.Contains(" has "))
            {
                throw ODataException.NotImplemented("Unsupported operator has", "$filter");
            }

            if ((validationSettings.AllowedLogicalOperators & AllowedLogicalOperators.Not) != AllowedLogicalOperators.Not &&
                rawFilterValue.Contains("not "))
            {
                throw ODataException.NotImplemented("Unsupported operator not", "$filter");
            }
        }
        private static void ValidateArithmeticOperators(ODataQueryOptions queryOptions, ODataValidationSettings validationSettings)
        {
            if (validationSettings.AllowedArithmeticOperators == AllowedArithmeticOperators.All)
            {
                return;
            }

            string rawFilterValue = queryOptions.RawValues.Filter;

            if ((validationSettings.AllowedArithmeticOperators & AllowedArithmeticOperators.Add) != AllowedArithmeticOperators.Add &&
                rawFilterValue.Contains(" add "))
            {
                throw ODataException.NotImplemented("Unsupported operator add", "$filter");
            }

            if ((validationSettings.AllowedArithmeticOperators & AllowedArithmeticOperators.Divide) != AllowedArithmeticOperators.Divide &&
                rawFilterValue.Contains(" div "))
            {
                throw ODataException.NotImplemented("Unsupported operator div", "$filter");
            }

            if ((validationSettings.AllowedArithmeticOperators & AllowedArithmeticOperators.Modulo) != AllowedArithmeticOperators.Modulo &&
                rawFilterValue.Contains(" mod "))
            {
                throw ODataException.NotImplemented("Unsupported operator mod", "$filter");
            }

            if ((validationSettings.AllowedArithmeticOperators & AllowedArithmeticOperators.Multiply) != AllowedArithmeticOperators.Multiply &&
                rawFilterValue.Contains(" mul "))
            {
                throw ODataException.NotImplemented("Unsupported operator mul", "$filter");
            }

            if ((validationSettings.AllowedArithmeticOperators & AllowedArithmeticOperators.Subtract) != AllowedArithmeticOperators.Subtract &&
                rawFilterValue.Contains(" sub "))
            {
                throw ODataException.NotImplemented("Unsupported operator sub", "$filter");
            }
        }
        /// <summary>
        /// override this method to restrict the binary operators inside the filter query. That includes all the logical operators except 'not' and all math operators.
        /// </summary>
        /// <remarks>
        /// This method is intended to be called from method overrides in subclasses. This method also supports unit-testing scenarios and is not intended to be called from user code.
        /// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance.
        /// </remarks>
        /// <param name="binaryOperatorNode"></param>
        /// <param name="settings"></param>
        public virtual void ValidateBinaryOperatorNode(BinaryOperatorNode binaryOperatorNode, ODataValidationSettings settings)
        {
            if (binaryOperatorNode == null)
            {
                throw Error.ArgumentNull("binaryOperatorNode");
            }

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

            // base case goes
            switch (binaryOperatorNode.OperatorKind)
            {
            case BinaryOperatorKind.Equal:
            case BinaryOperatorKind.NotEqual:
            case BinaryOperatorKind.And:
            case BinaryOperatorKind.GreaterThan:
            case BinaryOperatorKind.GreaterThanOrEqual:
            case BinaryOperatorKind.LessThan:
            case BinaryOperatorKind.LessThanOrEqual:
            case BinaryOperatorKind.Or:
                // binary logical operators
                ValidateLogicalOperator(binaryOperatorNode, settings);
                break;

            default:
                // math operators
                ValidateArithmeticOperator(binaryOperatorNode, settings);
                break;
            }
        }
        /// <summary>
        /// Override this method for the Arithmetic operators, including add, sub, mul, div, mod.
        /// </summary>
        /// <remarks>
        /// This method is intended to be called from method overrides in subclasses. This method also supports unit-testing scenarios and is not intended to be called from user code.
        /// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance.
        /// </remarks>
        /// <param name="binaryNode"></param>
        /// <param name="settings"></param>
        public virtual void ValidateArithmeticOperator(BinaryOperatorNode binaryNode, ODataValidationSettings settings)
        {
            if (binaryNode == null)
            {
                throw Error.ArgumentNull("binaryNode");
            }

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

            AllowedArithmeticOperators arithmeticOperator = ToArithmeticOperator(binaryNode);

            if ((settings.AllowedArithmeticOperators & arithmeticOperator) != arithmeticOperator)
            {
                // this means the given logical operator is not allowed
                throw new ODataException(Error.Format(SRResources.NotAllowedArithmeticOperator, arithmeticOperator, "AllowedArithmeticOperators"));
            }

            // recursion case goes here
            ValidateQueryNode(binaryNode.Left, settings);
            ValidateQueryNode(binaryNode.Right, settings);
        }
        /// <summary>
        /// Override this method for the navigation property node.
        /// </summary>
        /// <remarks>
        /// This method is intended to be called from method overrides in subclasses. This method also supports unit-testing scenarios and is not intended to be called from user code.
        /// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance.
        /// </remarks>
        /// <param name="sourceNode"></param>
        /// <param name="navigationProperty"></param>
        /// <param name="settings"></param>
        public virtual void ValidateNavigationPropertyNode(QueryNode sourceNode, IEdmNavigationProperty navigationProperty, ODataValidationSettings settings)
        {
            if (settings == null)
            {
                throw Error.ArgumentNull("settings");
            }

            // no default validation logic here

            // recursion
            if (sourceNode != null)
            {
                ValidateQueryNode(sourceNode, settings);
            }
        }
        /// <summary>
        /// Override this method to validate collection property accessor.
        /// </summary>
        /// <remarks>
        /// This method is intended to be called from method overrides in subclasses. This method also supports unit-testing scenarios and is not intended to be called from user code.
        /// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance.
        /// </remarks>
        /// <param name="propertyAccessNode"></param>
        /// <param name="settings"></param>
        public virtual void ValidateCollectionPropertyAccessNode(CollectionPropertyAccessNode propertyAccessNode, ODataValidationSettings settings)
        {
            if (propertyAccessNode == null)
            {
                throw Error.ArgumentNull("propertyAccessNode");
            }

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

            // no default validation logic here
            ValidateQueryNode(propertyAccessNode.Source, settings);
        }
        /// <summary>
        /// Override this method to validate Function calls, such as 'length', 'years', etc.
        /// </summary>
        /// <remarks>
        /// This method is intended to be called from method overrides in subclasses. This method also supports unit-testing scenarios and is not intended to be called from user code.
        /// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance.
        /// </remarks>
        /// <param name="node"></param>
        /// <param name="settings"></param>
        public virtual void ValidateSingleValueFunctionCallNode(SingleValueFunctionCallNode node, ODataValidationSettings settings)
        {
            if (node == null)
            {
                throw Error.ArgumentNull("node");
            }

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

            ValidateFunction(node.Name, settings);

            foreach (QueryNode argumentNode in node.Arguments)
            {
                ValidateQueryNode(argumentNode, settings);
            }
        }
        /// <summary>
        /// Override this method to validate the Not operator.
        /// </summary>
        /// <remarks>
        /// This method is intended to be called from method overrides in subclasses. This method also supports unit-testing scenarios and is not intended to be called from user code.
        /// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance.
        /// </remarks>
        /// <param name="unaryOperatorNode"></param>
        /// <param name="settings"></param>
        public virtual void ValidateUnaryOperatorNode(UnaryOperatorNode unaryOperatorNode, ODataValidationSettings settings)
        {
            ValidateQueryNode(unaryOperatorNode.Operand, settings);

            switch (unaryOperatorNode.OperatorKind)
            {
            case UnaryOperatorKind.Negate:
            case UnaryOperatorKind.Not:
                if ((settings.AllowedLogicalOperators & AllowedLogicalOperators.Not) != AllowedLogicalOperators.Not)
                {
                    throw new ODataException(Error.Format(SRResources.NotAllowedLogicalOperator, unaryOperatorNode.OperatorKind, "AllowedLogicalOperators"));
                }
                break;
            }
        }
        /// <summary>
        /// Override this method if you want to validate casts on entity collections.
        /// </summary>
        /// <remarks>
        /// This method is intended to be called from method overrides in subclasses. This method also supports unit-testing scenarios and is not intended to be called from user code.
        /// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance.
        /// </remarks>
        /// <param name="entityCollectionCastNode"></param>
        /// <param name="settings"></param>
        public virtual void ValidateEntityCollectionCastNode(EntityCollectionCastNode entityCollectionCastNode, ODataValidationSettings settings)
        {
            if (entityCollectionCastNode == null)
            {
                throw Error.ArgumentNull("entityCollectionCastNode");
            }

            ValidateQueryNode(entityCollectionCastNode.Source, settings);
        }
Beispiel #45
0
 public override void Validate(FilterQueryOption filterQueryOption, ODataValidationSettings settings)
 {
     ValidateQueryNode(filterQueryOption.FilterClause.Expression, settings);
 }
        private static void ValidateDateTimeFunctions(ODataQueryOptions queryOptions, ODataValidationSettings validationSettings)
        {
            if (validationSettings.AllowedFunctions == AllowedFunctions.AllFunctions ||
                validationSettings.AllowedFunctions == AllowedFunctions.AllDateTimeFunctions)
            {
                return;
            }

            string rawFilterValue = queryOptions.RawValues.Filter;

            if ((validationSettings.AllowedFunctions & AllowedFunctions.Date) != AllowedFunctions.Date &&
                rawFilterValue.Contains("date("))
            {
                throw ODataException.NotImplemented("Unsupported function date", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.Day) != AllowedFunctions.Day &&
                rawFilterValue.Contains("day("))
            {
                throw ODataException.NotImplemented("Unsupported function day", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.FractionalSeconds) != AllowedFunctions.FractionalSeconds &&
                rawFilterValue.Contains("fractionalseconds("))
            {
                throw ODataException.NotImplemented("Unsupported function fractionalseconds", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.Hour) != AllowedFunctions.Hour &&
                rawFilterValue.Contains("hour("))
            {
                throw ODataException.NotImplemented("Unsupported function hour", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.MaxDateTime) != AllowedFunctions.MaxDateTime &&
                rawFilterValue.Contains("maxdatetime("))
            {
                throw ODataException.NotImplemented("Unsupported function maxdatetime", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.MinDateTime) != AllowedFunctions.MinDateTime &&
                rawFilterValue.Contains("mindatetime("))
            {
                throw ODataException.NotImplemented("Unsupported function mindatetime", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.Minute) != AllowedFunctions.Minute &&
                rawFilterValue.Contains("minute("))
            {
                throw ODataException.NotImplemented("Unsupported function minute", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.Month) != AllowedFunctions.Month &&
                rawFilterValue.Contains("month("))
            {
                throw ODataException.NotImplemented("Unsupported function month", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.Now) != AllowedFunctions.Now &&
                rawFilterValue.Contains("now("))
            {
                throw ODataException.NotImplemented("Unsupported function now", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.Second) != AllowedFunctions.Second &&
                rawFilterValue.Contains("second("))
            {
                throw ODataException.NotImplemented("Unsupported function second", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.Time) != AllowedFunctions.Time &&
                (rawFilterValue.StartsWith("$filter=time(", StringComparison.Ordinal) || rawFilterValue.Contains(" time(")))
            {
                throw ODataException.NotImplemented("Unsupported function time", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.TotalOffsetMinutes) != AllowedFunctions.TotalOffsetMinutes &&
                rawFilterValue.Contains("totaloffsetminutes("))
            {
                throw ODataException.NotImplemented("Unsupported function totaloffsetminutes", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.TotalSeconds) != AllowedFunctions.TotalSeconds &&
                rawFilterValue.Contains("totalseconds("))
            {
                throw ODataException.NotImplemented("Unsupported function totalseconds", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.Year) != AllowedFunctions.Year &&
                rawFilterValue.Contains("year("))
            {
                throw ODataException.NotImplemented("Unsupported function year", "$filter");
            }
        }
Beispiel #47
0
 public override void ValidateAllNode(AllNode allNode,
                                      ODataValidationSettings settings)
 {
     base.ValidateAllNode(allNode, settings);
 }
        private static void ValidateStringFunctions(ODataQueryOptions queryOptions, ODataValidationSettings validationSettings)
        {
            if (validationSettings.AllowedFunctions == AllowedFunctions.AllFunctions ||
                validationSettings.AllowedFunctions == AllowedFunctions.AllStringFunctions)
            {
                return;
            }

            string rawFilterValue = queryOptions.RawValues.Filter;

            if ((validationSettings.AllowedFunctions & AllowedFunctions.Contains) != AllowedFunctions.Contains &&
                rawFilterValue.Contains("contains("))
            {
                throw ODataException.NotImplemented("Unsupported function contains", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.Concat) != AllowedFunctions.Concat &&
                rawFilterValue.Contains("concat("))
            {
                throw ODataException.NotImplemented("Unsupported function concat", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.EndsWith) != AllowedFunctions.EndsWith &&
                rawFilterValue.Contains("endswith("))
            {
                throw ODataException.NotImplemented("Unsupported function endswith", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.IndexOf) != AllowedFunctions.IndexOf &&
                rawFilterValue.Contains("indexof("))
            {
                throw ODataException.NotImplemented("Unsupported function indexof", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.Length) != AllowedFunctions.Length &&
                rawFilterValue.Contains("length("))
            {
                throw ODataException.NotImplemented("Unsupported function length", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.StartsWith) != AllowedFunctions.StartsWith &&
                rawFilterValue.Contains("startswith("))
            {
                throw ODataException.NotImplemented("Unsupported function startswith", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.Substring) != AllowedFunctions.Substring &&
                rawFilterValue.Contains("substring("))
            {
                throw ODataException.NotImplemented("Unsupported function substring", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.ToLower) != AllowedFunctions.ToLower &&
                rawFilterValue.Contains("tolower("))
            {
                throw ODataException.NotImplemented("Unsupported function tolower", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.ToUpper) != AllowedFunctions.ToUpper &&
                rawFilterValue.Contains("toupper("))
            {
                throw ODataException.NotImplemented("Unsupported function toupper", "$filter");
            }

            if ((validationSettings.AllowedFunctions & AllowedFunctions.Trim) != AllowedFunctions.Trim &&
                rawFilterValue.Contains("trim("))
            {
                throw ODataException.NotImplemented("Unsupported function trim", "$filter");
            }
        }
 public override void ValidateSingleValuePropertyAccessNode(SingleValuePropertyAccessNode propertyAccessNode, ODataValidationSettings settings)
 {
     if (restrictedProperties.Contains <string>(propertyAccessNode.Property.Name))
     {
         throw new ODataException(string.Format("{0} is an invalid filter property"));
     }
     base.ValidateSingleValuePropertyAccessNode(propertyAccessNode, settings);
 }
Beispiel #50
0
        /// <summary>
        /// Validates a <see cref="TopQueryOption" />.
        /// </summary>
        /// <param name="selectExpandQueryOption">The $select and $expand query.</param>
        /// <param name="validationSettings">The validation settings.</param>
        public virtual void Validate(SelectExpandQueryOption selectExpandQueryOption, ODataValidationSettings validationSettings)
        {
            if (selectExpandQueryOption == null)
            {
                throw Error.ArgumentNull("selectExpandQueryOption");
            }

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

            _orderByQueryValidator = new OrderByModelLimitationsValidator(selectExpandQueryOption.Context,
                                                                          _defaultQuerySettings.EnableOrderBy);
            _selectExpandQueryOption = selectExpandQueryOption;
            ValidateRestrictions(null, 0, selectExpandQueryOption.SelectExpandClause, null, validationSettings);

            if (validationSettings.MaxExpansionDepth > 0)
            {
                if (selectExpandQueryOption.LevelsMaxLiteralExpansionDepth < 0)
                {
                    selectExpandQueryOption.LevelsMaxLiteralExpansionDepth = validationSettings.MaxExpansionDepth;
                }
                else if (selectExpandQueryOption.LevelsMaxLiteralExpansionDepth > validationSettings.MaxExpansionDepth)
                {
                    throw new ODataException(Error.Format(
                                                 SRResources.InvalidExpansionDepthValue,
                                                 "LevelsMaxLiteralExpansionDepth",
                                                 "MaxExpansionDepth"));
                }

                ValidateDepth(selectExpandQueryOption.SelectExpandClause, validationSettings.MaxExpansionDepth);
            }
        }
Beispiel #51
0
        private void ValidateRestrictions(
            int?remainDepth,
            int currentDepth,
            SelectExpandClause selectExpandClause,
            IEdmNavigationProperty navigationProperty,
            ODataValidationSettings validationSettings)
        {
            IEdmModel edmModel = _selectExpandQueryOption.Context.Model;
            int?      depth    = remainDepth;

            if (remainDepth < 0)
            {
                throw new ODataException(
                          Error.Format(SRResources.MaxExpandDepthExceeded, currentDepth - 1, "MaxExpansionDepth"));
            }

            IEdmProperty       pathProperty;
            IEdmStructuredType pathStructuredType;

            if (navigationProperty == null)
            {
                pathProperty       = _selectExpandQueryOption.Context.TargetProperty;
                pathStructuredType = _selectExpandQueryOption.Context.TargetStructuredType;
            }
            else
            {
                pathProperty       = navigationProperty;
                pathStructuredType = navigationProperty.ToEntityType();
            }

            foreach (SelectItem selectItem in selectExpandClause.SelectedItems)
            {
                ExpandedNavigationSelectItem expandItem = selectItem as ExpandedNavigationSelectItem;
                if (expandItem != null)
                {
                    NavigationPropertySegment navigationSegment =
                        (NavigationPropertySegment)expandItem.PathToNavigationProperty.LastSegment;
                    IEdmNavigationProperty property = navigationSegment.NavigationProperty;
                    if (EdmLibHelpers.IsNotExpandable(property, edmModel))
                    {
                        throw new ODataException(Error.Format(SRResources.NotExpandablePropertyUsedInExpand,
                                                              property.Name));
                    }

                    if (edmModel != null)
                    {
                        ValidateOtherQueryOptionInExpand(property, edmModel, expandItem, validationSettings);
                        bool isExpandable;
                        ExpandConfiguration expandConfiguration;
                        isExpandable = EdmLibHelpers.IsExpandable(property.Name,
                                                                  pathProperty,
                                                                  pathStructuredType,
                                                                  edmModel,
                                                                  out expandConfiguration);
                        if (isExpandable)
                        {
                            int maxDepth = expandConfiguration.MaxDepth;
                            if (maxDepth > 0 && (remainDepth == null || maxDepth < remainDepth))
                            {
                                remainDepth = maxDepth;
                            }
                        }
                        else if (!isExpandable)
                        {
                            if (!_defaultQuerySettings.EnableExpand ||
                                (expandConfiguration != null && expandConfiguration.ExpandType == SelectExpandType.Disabled))
                            {
                                throw new ODataException(Error.Format(SRResources.NotExpandablePropertyUsedInExpand,
                                                                      property.Name));
                            }
                        }
                    }

                    if (remainDepth.HasValue)
                    {
                        remainDepth--;
                        if (expandItem.LevelsOption != null)
                        {
                            ValidateLevelsOption(expandItem.LevelsOption, remainDepth.Value, currentDepth + 1, edmModel,
                                                 property);
                        }
                    }

                    ValidateRestrictions(remainDepth, currentDepth + 1, expandItem.SelectAndExpand, property,
                                         validationSettings);
                    remainDepth = depth;
                }

                ValidateSelectItem(selectItem, pathProperty, pathStructuredType, edmModel);
            }
        }
        public void apply_to_should_use_enable_query_attribute(ApiDescription description)
        {
            // arrange
            var validationSettings = new ODataValidationSettings()
            {
                AllowedQueryOptions        = AllowedQueryOptions.None,
                AllowedArithmeticOperators = AllowedArithmeticOperators.None,
                AllowedLogicalOperators    = AllowedLogicalOperators.None,
                AllowedFunctions           = AllowedFunctions.None,
            };
            var settings   = new TestODataQueryOptionSettings();
            var convention = new ODataValidationSettingsConvention(validationSettings, settings);

            // act
            convention.ApplyTo(description);

            // assert
            description.ParameterDescriptions.Should().BeEquivalentTo(
                new[]
            {
                new
                {
                    Name                = "$select",
                    Documentation       = "Test",
                    Source              = FromUri,
                    ParameterDescriptor = new
                    {
                        ParameterName = "$select",
                        ParameterType = typeof(string),
                        Prefix        = "$",
                        IsOptional    = true,
                        DefaultValue  = default(object),
                    }
                },
                new
                {
                    Name                = "$expand",
                    Documentation       = "Test",
                    Source              = FromUri,
                    ParameterDescriptor = new
                    {
                        ParameterName = "$expand",
                        ParameterType = typeof(string),
                        Prefix        = "$",
                        IsOptional    = true,
                        DefaultValue  = default(object),
                    }
                },
                new
                {
                    Name                = "$filter",
                    Documentation       = "Test",
                    Source              = FromUri,
                    ParameterDescriptor = new
                    {
                        ParameterName = "$filter",
                        ParameterType = typeof(string),
                        Prefix        = "$",
                        IsOptional    = true,
                        DefaultValue  = default(object),
                    }
                },
            },
                options => options.ExcludingMissingMembers());
        }
        public void apply_to_should_use_model_bound_query_attributes()
        {
            // arrange
            var builder = new ODataConventionModelBuilder().EnableLowerCamelCase();

            builder.EntitySet <Order>("Orders");

            var validationSettings = new ODataValidationSettings()
            {
                AllowedQueryOptions        = AllowedQueryOptions.None,
                AllowedArithmeticOperators = AllowedArithmeticOperators.None,
                AllowedLogicalOperators    = AllowedLogicalOperators.None,
                AllowedFunctions           = AllowedFunctions.None,
            };
            var settings    = new TestODataQueryOptionSettings();
            var convention  = new ODataValidationSettingsConvention(validationSettings, settings);
            var model       = builder.GetEdmModel();
            var description = NewApiDescription(typeof(OrdersController), typeof(IEnumerable <Order>), model);

            // act
            convention.ApplyTo(description);

            // assert
            description.ParameterDescriptions.Should().BeEquivalentTo(
                new[]
            {
                new
                {
                    Name                = "$select",
                    Documentation       = "Test",
                    Source              = FromUri,
                    ParameterDescriptor = new
                    {
                        ParameterName = "$select",
                        ParameterType = typeof(string),
                        Prefix        = "$",
                        IsOptional    = true,
                        DefaultValue  = default(object),
                    }
                },
                new
                {
                    Name                = "$filter",
                    Documentation       = "Test",
                    Source              = FromUri,
                    ParameterDescriptor = new
                    {
                        ParameterName = "$filter",
                        ParameterType = typeof(string),
                        Prefix        = "$",
                        IsOptional    = true,
                        DefaultValue  = default(object),
                    }
                },
                new
                {
                    Name                = "$orderby",
                    Documentation       = "Test",
                    Source              = FromUri,
                    ParameterDescriptor = new
                    {
                        ParameterName = "$orderby",
                        ParameterType = typeof(string),
                        Prefix        = "$",
                        IsOptional    = true,
                        DefaultValue  = default(object),
                    }
                },
                new
                {
                    Name                = "$count",
                    Documentation       = "Test",
                    Source              = FromUri,
                    ParameterDescriptor = new
                    {
                        ParameterName = "$count",
                        ParameterType = typeof(bool),
                        Prefix        = "$",
                        IsOptional    = true,
                        DefaultValue  = (object)false,
                    }
                },
            },
                options => options.ExcludingMissingMembers());
        }