Esempio n. 1
0
        /// <summary>
        /// Build an ODataUriParser
        /// </summary>
        /// <param name="model">Model to use for metadata binding.</param>
        /// <param name="serviceRoot">Absolute URI of the service root.</param>
        /// <param name="uri">Absolute or relative URI to be parsed.</param>
        /// <param name="container">The optional dependency injection container to get related services for URI parsing.</param>
        public ODataUriParser(IEdmModel model, Uri serviceRoot, Uri uri, IServiceProvider container)
        {
            ExceptionUtils.CheckArgumentNotNull(uri, "uri");

            if (serviceRoot == null)
            {
                throw new ODataException(ODataErrorStrings.UriParser_NeedServiceRootForThisOverload);
            }

            if (!serviceRoot.IsAbsoluteUri)
            {
                throw new ODataException(ODataErrorStrings.UriParser_UriMustBeAbsolute(serviceRoot));
            }

            this.configuration = new ODataUriParserConfiguration(model, container);
            this.serviceRoot   = UriUtils.EnsureTaillingSlash(serviceRoot);
            this.uri           = uri.IsAbsoluteUri ? uri : UriUtils.UriToAbsoluteUri(this.ServiceRoot, uri);
            this.queryOptions  = QueryOptionUtils.ParseQueryOptions(this.uri);
        }
        /// <summary>
        /// Parses an <paramref name="orderBy "/> clause, binding
        /// the text into semantic nodes using the provided model.
        /// </summary>
        /// <param name="orderBy">String representation of the orderby expression.</param>
        /// <param name="configuration">The configuration used for binding.</param>
        /// <param name="odataPathInfo">The path info from Uri path.</param>
        /// <returns>An <see cref="OrderByClause"/> representing the metadata bound orderby expression.</returns>
        private OrderByClause ParseOrderByImplementation(string orderBy, ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo)
        {
            ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
            ExceptionUtils.CheckArgumentNotNull(configuration.Model, "model");
            ExceptionUtils.CheckArgumentNotNull(orderBy, "orderBy");

            // Get the syntactic representation of the orderby expression
            UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(configuration.Settings.OrderByLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier);
            var orderByQueryTokens = expressionParser.ParseOrderBy(orderBy);

            // Bind it to metadata
            BindingState state = CreateBindingState(configuration, odataPathInfo);

            MetadataBinder binder        = new MetadataBinder(state);
            OrderByBinder  orderByBinder = new OrderByBinder(binder.Bind);
            OrderByClause  orderByClause = orderByBinder.BindOrderBy(state, orderByQueryTokens);

            return(orderByClause);
        }
        /// <summary>
        /// Parses a <paramref name="filter"/> clause, binding
        /// the text into semantic nodes using the provided model.
        /// </summary>
        /// <param name="filter">String representation of the filter expression.</param>
        /// <param name="configuration">The configuration used for binding.</param>
        /// <param name="odataPathInfo">The path info from Uri path.</param>
        /// <returns>A <see cref="FilterClause"/> representing the metadata bound filter expression.</returns>
        private FilterClause ParseFilterImplementation(string filter, ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo)
        {
            ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
            ExceptionUtils.CheckArgumentNotNull(odataPathInfo, "odataPathInfo");
            ExceptionUtils.CheckArgumentNotNull(filter, "filter");

            // Get the syntactic representation of the filter expression
            UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(configuration.Settings.FilterLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier);
            QueryToken filterToken = expressionParser.ParseFilter(filter);

            // Bind it to metadata
            BindingState state = CreateBindingState(configuration, odataPathInfo);

            MetadataBinder binder       = new MetadataBinder(state);
            FilterBinder   filterBinder = new FilterBinder(binder.Bind, state);
            FilterClause   boundNode    = filterBinder.BindFilter(filterToken);

            return(boundNode);
        }
Esempio n. 4
0
        public SelectExpandBinder(ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo, BindingState state)
        {
            ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
            ExceptionUtils.CheckArgumentNotNull(odataPathInfo.TargetStructuredType, "edmType");

            this.configuration    = configuration;
            this.edmType          = odataPathInfo.TargetStructuredType;
            this.navigationSource = odataPathInfo.TargetNavigationSource;
            this.parsedSegments   = odataPathInfo.Segments.ToList();
            this.state            = state;

            if (this.state != null)
            {
                this.resourcePathNavigationSource = this.state.ResourcePathNavigationSource;
            }
            else
            {
                this.resourcePathNavigationSource = odataPathInfo.TargetNavigationSource;
            }
        }
        /// <summary>
        /// Parses the <paramref name="compute"/> clause, binding
        /// the text into a metadata-bound list of compuations using the provided model.
        /// </summary>
        /// <param name="compute">String representation of the compute expression from the URI.</param>
        /// <param name="configuration">The configuration used for binding.</param>
        /// <param name="odataPathInfo">The path info from Uri path.</param>
        /// <returns>A <see cref="ComputeClause"/> representing the metadata bound compute expression.</returns>
        private static ComputeClause ParseComputeImplementation(string compute, ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo)
        {
            ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
            ExceptionUtils.CheckArgumentNotNull(compute, "compute");

            // Get the syntactic representation of the apply expression
            UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(configuration.Settings.FilterLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier);
            ComputeToken             computeToken     = expressionParser.ParseCompute(compute);

            // Bind it to metadata
            BindingState state = new BindingState(configuration);

            state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(odataPathInfo.TargetEdmType.ToTypeReference(), odataPathInfo.TargetNavigationSource);
            state.RangeVariables.Push(state.ImplicitRangeVariable);
            MetadataBinder binder        = new MetadataBinder(state);
            ComputeBinder  computeBinder = new ComputeBinder(binder.Bind);
            ComputeClause  boundNode     = computeBinder.BindCompute(computeToken);

            return(boundNode);
        }
        /// <summary>
        /// Parses an <paramref name="apply"/> clause, binding
        /// the text into a metadata-bound or dynamic properties to be applied using the provided model.
        /// </summary>
        /// <param name="apply">String representation of the apply expression.</param>
        /// <param name="configuration">The configuration used for binding.</param>
        /// <param name="odataPathInfo">The path info from Uri path.</param>
        /// <returns>A <see cref="ApplyClause"/> representing the metadata bound apply expression.</returns>
        private static ApplyClause ParseApplyImplementation(string apply, ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo)
        {
            ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
            ExceptionUtils.CheckArgumentNotNull(apply, "apply");

            // Get the syntactic representation of the apply expression
            UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(configuration.Settings.FilterLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier);
            var applyTokens = expressionParser.ParseApply(apply);

            // Bind it to metadata
            BindingState state = new BindingState(configuration, odataPathInfo.Segments.ToList());

            state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(odataPathInfo.TargetEdmType.ToTypeReference(), odataPathInfo.TargetNavigationSource);
            state.RangeVariables.Push(state.ImplicitRangeVariable);
            MetadataBinder binder      = new MetadataBinder(state);
            ApplyBinder    applyBinder = new ApplyBinder(binder.Bind, state, configuration, odataPathInfo);
            ApplyClause    boundNode   = applyBinder.BindApply(applyTokens);

            return(boundNode);
        }
        /// <summary>
        /// Add semantic meaning to a Select or Expand Token
        /// </summary>
        /// <param name="odataPathInfo">The path info from Uri path.</param>
        /// <param name="expandToken">the syntactically parsed expand token</param>
        /// <param name="selectToken">the syntactically parsed select token</param>
        /// <param name="configuration">The configuration to use for parsing.</param>
        /// <param name="state">The state of binding.</param>
        /// <returns>A select expand clause bound to metadata.</returns>
        public static SelectExpandClause Bind(
            ODataPathInfo odataPathInfo,
            ExpandToken expandToken,
            SelectToken selectToken,
            ODataUriParserConfiguration configuration,
            BindingState state)
        {
            ExpandToken normalizedExpand = ExpandTreeNormalizer.NormalizeExpandTree(expandToken);
            SelectToken normalizedSelect = SelectTreeNormalizer.NormalizeSelectTree(selectToken);

            SelectExpandBinder selectExpandBinder = new SelectExpandBinder(configuration, odataPathInfo, state);

            SelectExpandClause clause = selectExpandBinder.Bind(normalizedExpand, normalizedSelect);

            SelectExpandClauseFinisher.AddExplicitNavPropLinksWhereNecessary(clause);

            new ExpandDepthAndCountValidator(configuration.Settings.MaximumExpansionDepth, configuration.Settings.MaximumExpansionCount).Validate(clause);

            return(clause);
        }
        /// <summary>
        /// Add semantic meaning to a Select or Expand Token
        /// </summary>
        /// <param name="odataPathInfo">The path info from Uri path.</param>
        /// <param name="expandToken">the syntactically parsed expand token</param>
        /// <param name="selectToken">the syntactically parsed select token</param>
        /// <param name="configuration">The configuration to use for parsing.</param>
        /// <returns>A select expand clause bound to metadata.</returns>
        public SelectExpandClause Bind(
            ODataPathInfo odataPathInfo,
            ExpandToken expandToken,
            SelectToken selectToken,
            ODataUriParserConfiguration configuration)
        {
            ExpandToken unifiedSelectExpandToken = SelectExpandSyntacticUnifier.Combine(expandToken, selectToken);

            ExpandTreeNormalizer expandTreeNormalizer        = new ExpandTreeNormalizer();
            ExpandToken          normalizedSelectExpandToken = expandTreeNormalizer.NormalizeExpandTree(unifiedSelectExpandToken);

            SelectExpandBinder selectExpandBinder = new SelectExpandBinder(configuration, odataPathInfo);
            SelectExpandClause clause             = selectExpandBinder.Bind(normalizedSelectExpandToken);

            SelectExpandClauseFinisher.AddExplicitNavPropLinksWhereNecessary(clause);

            new ExpandDepthAndCountValidator(configuration.Settings.MaximumExpansionDepth, configuration.Settings.MaximumExpansionCount).Validate(clause);

            return(clause);
        }
Esempio n. 9
0
        private static BindingState CreateBindingState(ODataUriParserConfiguration config,
                                                       IEdmNavigationSource targetNavigationSource, IEdmTypeReference elementType,
                                                       HashSet <EndPathToken> generatedProperties = null, bool collapsed = false)
        {
            if (targetNavigationSource == null && elementType == null)
            {
                return(null);
            }

            BindingState state = new BindingState(config)
            {
                ImplicitRangeVariable =
                    NodeFactory.CreateImplicitRangeVariable(elementType != null ? elementType :
                                                            targetNavigationSource.EntityType().ToTypeReference(), targetNavigationSource)
            };

            state.RangeVariables.Push(state.ImplicitRangeVariable);
            state.AggregatedPropertyNames = generatedProperties;
            state.IsCollapsed             = collapsed;
            return(state);
        }
Esempio n. 10
0
        private static BindingState CreateBindingState(ODataUriParserConfiguration config,
                                                       IEdmNavigationSource resourcePathNavigationSource, IEdmNavigationSource targetNavigationSource,
                                                       IEdmTypeReference elementType, HashSet <EndPathToken> generatedProperties = null,
                                                       bool collapsed = false)
        {
            if (targetNavigationSource == null && elementType == null)
            {
                return(null);
            }

            // For example if we have https://url/Books?$expand=Authors($filter=Name eq $it/Name)
            // $filter=Name will reference Authors(the expanded entity).
            // $it/Name will reference Books(the resource identified by the path).
            // The BindingState ImplicitRangeVariable property will store the $it that references the expanded/selected item (The Implicit Range Variable).
            // We add to the Stack, the $it that references the resource identified by the path (The Explicit Range Variable).

            BindingState state = new BindingState(config)
            {
                ImplicitRangeVariable =
                    NodeFactory.CreateImplicitRangeVariable(elementType != null ? elementType :
                                                            targetNavigationSource.EntityType().ToTypeReference(), targetNavigationSource)
            };

            state.AggregatedPropertyNames      = generatedProperties;
            state.IsCollapsed                  = collapsed;
            state.ResourcePathNavigationSource = resourcePathNavigationSource;

            if (resourcePathNavigationSource != null)
            {
                // This $it rangeVariable will be added the Stack.
                // We are adding a rangeVariable whose navigationSource is the resource path entity set.
                // ODATA spec: Example 106 http://docs.oasis-open.org/odata/odata/v4.01/csprd05/part2-url-conventions/odata-v4.01-csprd05-part2-url-conventions.html#sec_it
                RangeVariable explicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(
                    resourcePathNavigationSource.EntityType().ToTypeReference(), resourcePathNavigationSource);
                state.RangeVariables.Push(explicitRangeVariable);
            }

            return(state);
        }
Esempio n. 11
0
        /// <summary>
        /// Parses the <paramref name="select"/> and <paramref name="expand"/> clauses, binding
        /// the text into a metadata-bound list of properties to be selected using the provided model.
        /// </summary>
        /// <param name="select">String representation of the select expression from the URI.</param>
        /// <param name="expand">String representation of the expand expression from the URI.</param>
        /// <param name="configuration">The configuration used for binding.</param>
        /// <param name="odataPathInfo">The path info from Uri path.</param>
        /// <returns>A <see cref="SelectExpandClause"/> representing the metadata bound select and expand expression.</returns>
        private static SelectExpandClause ParseSelectAndExpandImplementation(string select, string expand, ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo)
        {
            ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
            ExceptionUtils.CheckArgumentNotNull(configuration.Model, "model");

            ExpandToken expandTree;
            SelectToken selectTree;

            // syntactic pass , pass in the expand parent entity type name, in case expand option contains star, will get all the parent entity navigation properties (both declared and dynamical).
            SelectExpandSyntacticParser.Parse(select, expand, odataPathInfo.TargetStructuredType, configuration, out expandTree, out selectTree);

            // semantic pass
            return(SelectExpandSemanticBinder.Bind(odataPathInfo, expandTree, selectTree, configuration));
        }
Esempio n. 12
0
 /// <summary>
 /// Constructs a <see cref="BindingState"/> with the given <paramref name="configuration"/>.
 /// </summary>
 /// <param name="configuration">The configuration used for binding.</param>
 internal BindingState(ODataUriParserConfiguration configuration)
 {
     ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
     this.configuration         = configuration;
     this.BindingRecursionDepth = 0;
 }
        /// <summary>
        /// Tries to parse a collection of function parameters for path.
        /// </summary>
        /// <param name="parenthesisExpression">The contents of the parentheses portion of the current path segment.</param>
        /// <param name="configuration">The ODataUriParserConfiguration to create a UriQueryExpressionParser.</param>
        /// <param name="splitParameters">The parameters if they were successfully split.</param>
        /// <returns>Whether the parameters could be split.</returns>
        internal static bool TrySplitOperationParameters(string parenthesisExpression, ODataUriParserConfiguration configuration, out ICollection <FunctionParameterToken> splitParameters)
        {
            ExpressionLexer          lexer  = new ExpressionLexer(parenthesisExpression, true /*moveToFirstToken*/, false /*useSemicolonDelimeter*/, true /*parsingFunctionParameters*/);
            UriQueryExpressionParser parser = new UriQueryExpressionParser(configuration.Settings.FilterLimit, lexer);
            var ret = parser.TrySplitOperationParameters(ExpressionTokenKind.End, out splitParameters);

            // check duplicate names
            if (splitParameters.Select(t => t.ParameterName).Distinct().Count() != splitParameters.Count)
            {
                throw new ODataException(ODataErrorStrings.FunctionCallParser_DuplicateParameterOrEntityKeyName);
            }

            return(ret);
        }