Beispiel #1
0
        /// <summary>
        /// Creates a list of path segments for the specified URI query.
        /// </summary>
        /// <param name="queryUri">The absolute URI of the request.</param>
        /// <param name="serviceBaseUri">The service base URI for the request.</param>
        /// <returns>The <see cref="QueryToken"/> representing the query path.</returns>
        private QueryToken CreatePathSegments(Uri queryUri, Uri serviceBaseUri)
        {
            Debug.Assert(queryUri != null, "queryUri != null");
            Debug.Assert(serviceBaseUri != null, "serviceBaseUri != null");

            //// This method is a no-metadata, lexical only copy of RequestUriProcessor.CreateSegments

            List <string> uriSegments = this.EnumerateSegments(queryUri, serviceBaseUri);

            Debug.Assert(uriSegments.Count <= this.maxDepth, "uriSegments.Count <= this.maxDepth");

            // The segment before the one being processed
            SegmentQueryToken parentNode = null;

            foreach (string uriSegment in uriSegments)
            {
                Debug.Assert(uriSegment != null, "uriSegment != null");

                string segmentIdentifier;
                bool   hasKeyValues    = ExtractSegmentIdentifier(uriSegment, out segmentIdentifier);
                string keyValuesString = hasKeyValues ? uriSegment.Substring(segmentIdentifier.Length) : null;

                SegmentQueryToken segment = new SegmentQueryToken()
                {
                    Name        = segmentIdentifier,
                    Parent      = parentNode,
                    NamedValues = hasKeyValues ? ParseKeyValues(keyValuesString) : null
                };

                parentNode = segment;
            }

            return(parentNode);
        }
        /// <summary>
        /// Create a new SegmentQueryToken given the name and parent and namedValues if any
        /// </summary>
        /// <param name="name">The name of the segment, the identifier.</param>
        /// <param name="parent">The parent segment, or null if this is the root segment.</param>
        /// <param name="namedValues">The named values in the key lookup for this segment.</param>
        public SegmentQueryToken(string name, SegmentQueryToken parent, IEnumerable<NamedValue> namedValues)
        {
            // We allow an "empty" name segment so we can create one for the case of a service-document URL (which has no path)
            ExceptionUtils.CheckArgumentNotNull(name, "name");

            this.name = name;
            this.parent = parent;
            this.namedValues = namedValues == null ? null : new ReadOnlyEnumerable<NamedValue>(namedValues);
        }
        /// <summary>
        /// Parses the <paramref name="queryUri"/> and returns a new instance of <see cref="QueryToken"/>
        /// describing the query path specified by the URI.
        /// </summary>
        /// <param name="queryUri">The absolute URI which holds the query to parse. This must be a path relative to the <paramref name="serviceBaseUri"/>.</param>
        /// <param name="serviceBaseUri">The base URI of the service.</param>
        /// <returns>A new instance of <see cref="QueryToken"/> which represents the query path specified in the <paramref name="queryUri"/>.
        /// The result QueryToken is just a lexical representation.</returns>
        internal QueryToken ParseUri(Uri queryUri, Uri serviceBaseUri)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(queryUri != null, "queryUri != null");
            Debug.Assert(serviceBaseUri != null, "serviceBaseUri != null");

            QueryToken path = this.CreatePathSegments(queryUri, serviceBaseUri);
            if (path == null)
            {
                // No segments were found - the service document query
                // The lexical representation of the service document is an identifier with an empty name
                path = new SegmentQueryToken(string.Empty, null, null);
            }

            return path;
        }
Beispiel #4
0
        /// <summary>
        /// Parses the <paramref name="queryUri"/> and returns a new instance of <see cref="QueryToken"/>
        /// describing the query path specified by the URI.
        /// </summary>
        /// <param name="queryUri">The absolute URI which holds the query to parse. This must be a path relative to the <paramref name="serviceBaseUri"/>.</param>
        /// <param name="serviceBaseUri">The base URI of the service.</param>
        /// <returns>A new instance of <see cref="QueryToken"/> which represents the query path specified in the <paramref name="queryUri"/>.
        /// The result QueryToken is just a lexical representation.</returns>
        internal QueryToken ParseUri(Uri queryUri, Uri serviceBaseUri)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(queryUri != null, "queryUri != null");
            Debug.Assert(serviceBaseUri != null, "serviceBaseUri != null");

            QueryToken path = this.CreatePathSegments(queryUri, serviceBaseUri);

            if (path == null)
            {
                // No segments were found - the service document query
                // The lexical representation of the service document is an identifier with an empty name
                path = new SegmentQueryToken(string.Empty, null, null);
            }

            return(path);
        }
        public static string GetOperationName(Uri requestUri, Uri baseAddress)
        {
            try
            {
                // remove the query part as they are irrelevant here and we dont want to fail parsing them.
                Uri               requestUriWithoutQuerypart = new Uri(requestUri.GetLeftPart(UriPartial.Path));
                SyntacticTree     syntacticTree = SyntacticTree.ParseUri(requestUriWithoutQuerypart, baseAddress);
                SegmentQueryToken lastSegment   = syntacticTree.Path as SegmentQueryToken;
                if (lastSegment != null && !String.IsNullOrEmpty(lastSegment.Name))
                {
                    return(lastSegment.Name);
                }
            }
            catch (Exception)
            {
            }

            return(null);
        }
        /// <summary>
        /// Write the descriptor path token as URI part to this builder.
        /// </summary>
        /// <param name="segment">To write as URI part.</param>
        protected virtual void WriteSegment(SegmentQueryToken segment)
        {
            ExceptionUtils.CheckArgumentNotNull(segment, "segment");

            // If this desriptor have no path, it is a service-document Url, so just quit
            if (string.IsNullOrEmpty(segment.Name))
            {
                return;
            }

            if (segment.Parent != null)
            {
                this.WriteSegment(segment.Parent);
                this.builder.Append(ExpressionConstants.SymbolForwardSlash);
            }

            this.builder.Append(segment.Name);

            if (segment.NamedValues != null)
            {
                this.builder.Append(ExpressionConstants.SymbolOpenParen);

                bool needComma = false;
                foreach (NamedValue nv in segment.NamedValues)
                {
                    if (needComma)
                    {
                        this.builder.Append(ExpressionConstants.SymbolComma);
                    }

                    this.builder.Append(nv.Name);
                    this.builder.Append(ExpressionConstants.SymbolEqual);
                    this.WriteLiteral(nv.Value);
                    needComma = true;
                }

                this.builder.Append(ExpressionConstants.SymbolClosedParen);
            }
        }
 /// <summary>
 /// Create a new StarQueryToken given the parent (if any).
 /// </summary>
 /// <param name="keyword">The keyword kind of the segment.</param>
 /// <param name="parent">The parent segment, or null if this is the root segment.</param>
 public KeywordSegmentQueryToken(KeywordKind keyword, SegmentQueryToken parent)
     : base(QueryTokenUtils.GetNameFromKeywordKind(keyword), parent, null)
 {
     this.keyword = keyword;
 }
 protected virtual QueryNode BindNonRootSegment(SegmentQueryToken segmentToken)
 {
     var parent = Bind(segmentToken.Parent);
     if (parent is SingleValueQueryNode)
     {
         var parentType = (parent as SingleValueQueryNode).TypeReference.Definition;
         if (parentType is IEdmEntityType)
         {
             var parentEntityType = parentType as IEdmEntityType;
             var targetProperty = parentEntityType.Properties().FirstOrDefault(p => p.Name.Equals(segmentToken.Name));
             if (targetProperty != null)
             {
                 if (targetProperty is IEdmNavigationProperty)
                 {
                     var targetNavProperty = targetProperty as IEdmNavigationProperty;
                         return new NavigationPropertyNode
                             {
                                 NavigationProperty = targetNavProperty,
                                 Source = parent
                             };
                 }
                 if (targetProperty is IEdmStructuralProperty)
                 {
                     return new PropertyAccessQueryNode
                         {
                             Source = parent as SingleValueQueryNode,
                             Property = targetProperty
                         };
                 }
             }
         }
     }
     throw new NotImplementedException();
 }
        /// <summary>
        /// Need to revert this.
        /// </summary>
        /// <param name="segmentToken">Need to revert this.</param>
        /// <returns>Need to revert this.</returns>
        protected virtual QueryNode BindSegment(SegmentQueryToken segmentToken)
        {
            ExceptionUtils.CheckArgumentNotNull(segmentToken, "segmentToken");
            ExceptionUtils.CheckArgumentNotNull(segmentToken.Name, "segmentToken.Name");

            if (segmentToken.Parent == null)
            {
                return this.BindRootSegment(segmentToken);
            }
            else
            {
                return this.BindNonRootSegment(segmentToken);
                // TODO: return this.BindNonRootSegment(segmentToken);
                throw new NotImplementedException();
            }
        }
Beispiel #10
0
        /// <summary>
        /// Binds a service operation segment.
        /// </summary>
        /// <param name="segmentToken">The segment which represents a service operation.</param>
        /// <param name="serviceOperation">The service operation to bind.</param>
        /// <returns>The bound node.</returns>
        private QueryNode BindServiceOperation(SegmentQueryToken segmentToken, IEdmFunctionImport serviceOperation)
        {
            Debug.Assert(segmentToken != null, "segmentToken != null");
            Debug.Assert(serviceOperation != null, "serviceOperation != null");
            Debug.Assert(segmentToken.Name == serviceOperation.Name, "The segment represents a different service operation.");

            //// This is a metadata copy of the RequestUriProcessor.CreateSegmentForServiceOperation

            //// The WCF DS checks the verb in this place, we can't do that here

            // All service operations other than those returning IQueryable MUST NOT have () appended to the URI
            // V1/V2 behavior: if it's IEnumerable<T>, we do not allow () either, because it's not further composable.
            ODataServiceOperationResultKind? resultKind = serviceOperation.GetServiceOperationResultKind(this.model);
            if (resultKind != ODataServiceOperationResultKind.QueryWithMultipleResults && segmentToken.NamedValues != null)
            {
                throw new ODataException(Strings.MetadataBinder_NonQueryableServiceOperationWithKeyLookup(segmentToken.Name));
            }

            if (!resultKind.HasValue)
            {
                throw new ODataException(Strings.MetadataBinder_ServiceOperationWithoutResultKind(serviceOperation.Name));
            }

            IEnumerable<QueryNode> serviceOperationParameters = this.BindServiceOperationParameters(serviceOperation);
            switch (resultKind.Value)
            {
                case ODataServiceOperationResultKind.QueryWithMultipleResults:
                    if (serviceOperation.ReturnType.TypeKind() != EdmTypeKind.Entity)
                    {
                        throw new ODataException(Strings.MetadataBinder_QueryServiceOperationOfNonEntityType(serviceOperation.Name, resultKind.Value.ToString(), serviceOperation.ReturnType.ODataFullName()));
                    }

                    CollectionServiceOperationQueryNode collectionServiceOperationQueryNode = new CollectionServiceOperationQueryNode()
                    {
                        ServiceOperation = serviceOperation,
                        Parameters = serviceOperationParameters
                    };

                    if (segmentToken.NamedValues != null)
                    {
                        return this.BindKeyValues(collectionServiceOperationQueryNode, segmentToken.NamedValues);
                    }
                    else
                    {
                        return collectionServiceOperationQueryNode;
                    }

                case ODataServiceOperationResultKind.QueryWithSingleResult:
                    if (!serviceOperation.ReturnType.IsODataEntityTypeKind())
                    {
                        throw new ODataException(Strings.MetadataBinder_QueryServiceOperationOfNonEntityType(serviceOperation.Name, resultKind.Value.ToString(), serviceOperation.ReturnType.ODataFullName()));
                    }

                    return new SingleValueServiceOperationQueryNode()
                    {
                        ServiceOperation = serviceOperation,
                        Parameters = serviceOperationParameters
                    };

                case ODataServiceOperationResultKind.DirectValue:
                    if (serviceOperation.ReturnType.IsODataPrimitiveTypeKind())
                    {
                        // Direct primitive values are composable, $value is allowed on them.
                        return new SingleValueServiceOperationQueryNode()
                        {
                            ServiceOperation = serviceOperation,
                            Parameters = serviceOperationParameters
                        };
                    }
                    else
                    {
                        // Direct non-primitive values are not composable at all
                        return new UncomposableServiceOperationQueryNode()
                        {
                            ServiceOperation = serviceOperation,
                            Parameters = serviceOperationParameters
                        };
                    }

                case ODataServiceOperationResultKind.Enumeration:
                case ODataServiceOperationResultKind.Void:
                    // Enumeration and void service operations are not composable
                    return new UncomposableServiceOperationQueryNode()
                    {
                        ServiceOperation = serviceOperation,
                        Parameters = serviceOperationParameters
                    };

                default:
                    throw new ODataException(Strings.General_InternalError(InternalErrorCodes.MetadataBinder_BindServiceOperation));
            }
        }
Beispiel #11
0
        /// <summary>
        /// Binds a root path segment.
        /// </summary>
        /// <param name="segmentToken">The segment to bind.</param>
        /// <returns>The bound node.</returns>
        private QueryNode BindRootSegment(SegmentQueryToken segmentToken)
        {
            Debug.Assert(segmentToken != null, "segmentToken != null");
            Debug.Assert(segmentToken.Parent == null, "Only root segments should be allowed here.");
            Debug.Assert(!string.IsNullOrEmpty(segmentToken.Name), "!string.IsNullOrEmpty(segmentToken.Name)");

            //// This is a metadata-only version of the RequestUriProcessor.CreateFirstSegment.

            if (segmentToken.Name == UriQueryConstants.MetadataSegment)
            {
                // TODO: $metadata segment parsing - no key values are allowed.
                throw new NotImplementedException();
            }

            if (segmentToken.Name == UriQueryConstants.BatchSegment)
            {
                // TODO: $batch segment parsing - no key values are allowed.
                throw new NotImplementedException();
            }

            // TODO: WCF DS checks for $count here first and fails. But not for the other $ segments.
            // which means other $segments get to SO resolution. On the other hand the WCF DS would eventually fail if an SO started with $.

            // Look for a service operation
            IEdmFunctionImport serviceOperation = this.model.TryResolveServiceOperation(segmentToken.Name);
            if (serviceOperation != null)
            {
                return this.BindServiceOperation(segmentToken, serviceOperation);
            }

            // TODO: Content-ID reference resolution. Do we actually do anything here or do we perform this through extending the metadata binder?

            // Look for an entity set.
            IEdmEntitySet entitySet = this.model.TryResolveEntitySet(segmentToken.Name);
            if (entitySet == null)
            {
                throw new ODataException(Strings.MetadataBinder_RootSegmentResourceNotFound(segmentToken.Name));
            }

            EntitySetQueryNode entitySetQueryNode = new EntitySetQueryNode()
            {
                EntitySet = entitySet
            };

            if (segmentToken.NamedValues != null)
            {
                return this.BindKeyValues(entitySetQueryNode, segmentToken.NamedValues);
            }

            return entitySetQueryNode;
        }
        /// <summary>
        /// Binds a <see cref="SegmentQueryToken"/>.
        /// </summary>
        /// <param name="segmentToken">The segment token to bind.</param>
        /// <returns>The bound node.</returns>
        protected virtual QueryNode BindSegment(SegmentQueryToken segmentToken)
        {
            ExceptionUtils.CheckArgumentNotNull(segmentToken, "segmentToken");
            ExceptionUtils.CheckArgumentStringNotNullOrEmpty(segmentToken.Name, "segmentToken.Name");

            if (segmentToken.Parent == null)
            {
                return this.BindRootSegment(segmentToken);
            }
            else
            {
            	return BindNonRootSegment(segmentToken);
            }
        }
 /// <summary>
 /// Create a new StarQueryToken given the parent (if any).
 /// </summary>
 /// <param name="keyword">The keyword kind of the segment.</param>
 /// <param name="parent">The parent segment, or null if this is the root segment.</param>
 public KeywordSegmentQueryToken(KeywordKind keyword, SegmentQueryToken parent)
     : base(QueryTokenUtils.GetNameFromKeywordKind(keyword), parent, null)
 {
     this.keyword = keyword;
 }
        /// <summary>
        /// Write the descriptor path token as URI part to this builder.
        /// </summary>
        /// <param name="segment">To write as URI part.</param>
        protected virtual void WriteSegment(SegmentQueryToken segment)
        {
            ExceptionUtils.CheckArgumentNotNull(segment, "segment");

            // If this desriptor have no path, it is a service-document Url, so just quit
            if (string.IsNullOrEmpty(segment.Name))
            {
                return;
            }

            if (segment.Parent != null)
            {
                this.WriteSegment(segment.Parent);
                this.builder.Append(ExpressionConstants.SymbolForwardSlash);
            }

            this.builder.Append(segment.Name);

            if (segment.NamedValues != null)
            {
                this.builder.Append(ExpressionConstants.SymbolOpenParen);

                bool needComma = false;
                foreach (NamedValue nv in segment.NamedValues)
                {
                    if (needComma)
                    {
                        this.builder.Append(ExpressionConstants.SymbolComma);
                    }

                    this.builder.Append(nv.Name);
                    this.builder.Append(ExpressionConstants.SymbolEqual);
                    this.WriteLiteral(nv.Value);
                    needComma = true;
                }

                this.builder.Append(ExpressionConstants.SymbolClosedParen);
            }
        }
        /// <summary>
        /// Creates a list of path segments for the specified URI query.
        /// </summary>
        /// <param name="queryUri">The absolute URI of the request.</param>
        /// <param name="serviceBaseUri">The service base URI for the request.</param>
        /// <returns>The <see cref="QueryToken"/> representing the query path.</returns>
        private QueryToken CreatePathSegments(Uri queryUri, Uri serviceBaseUri)
        {
            Debug.Assert(queryUri != null, "queryUri != null");
            Debug.Assert(serviceBaseUri != null, "serviceBaseUri != null");

            //// This method is a no-metadata, lexical only copy of RequestUriProcessor.CreateSegments

            List<string> uriSegments = this.EnumerateSegments(queryUri, serviceBaseUri);
            Debug.Assert(uriSegments.Count <= this.maxDepth, "uriSegments.Count <= this.maxDepth");

            // The segment before the one being processed
            SegmentQueryToken parentNode = null;

            foreach (string uriSegment in uriSegments)
            {
                Debug.Assert(uriSegment != null, "uriSegment != null");

                string segmentIdentifier;
                bool hasKeyValues = ExtractSegmentIdentifier(uriSegment, out segmentIdentifier);
                string keyValuesString = hasKeyValues ? uriSegment.Substring(segmentIdentifier.Length) : null;

                SegmentQueryToken segment = new SegmentQueryToken()
                {
                    Name = segmentIdentifier,
                    Parent = parentNode,
                    NamedValues = hasKeyValues ? ParseKeyValues(keyValuesString) : null
                };

                parentNode = segment;
            }

            return parentNode;
        }