Пример #1
0
        private void ApplyNavigationProperty(ODataNavigationLink navigationLink, IEdmNavigationProperty navigationProperty, object entityResource, ODataDeserializerContext readContext)
        {
            ODataNavigationLinkAnnotation navigationLinkAnnotation = navigationLink.GetAnnotation <ODataNavigationLinkAnnotation>();

            Contract.Assert(navigationLinkAnnotation != null, "navigationLinkAnnotation != null");
            Contract.Assert(navigationLink.IsCollection.HasValue, "We should know the cardinality of the navigation link by now.");

            foreach (ODataItem childItem in navigationLinkAnnotation)
            {
                ODataEntityReferenceLink entityReferenceLink = childItem as ODataEntityReferenceLink;
                if (entityReferenceLink != null)
                {
                    // ignore links.
                    continue;
                }

                ODataFeed feed = childItem as ODataFeed;
                if (feed != null)
                {
                    ApplyFeedInNavigationProperty(navigationProperty, entityResource, feed, readContext);
                    continue;
                }

                // It must be entry by now.
                ODataEntry entry = (ODataEntry)childItem;
                if (entry != null)
                {
                    ApplyEntryInNavigationProperty(navigationProperty, entityResource, entry, readContext);
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Applies a navigation link as a navigation property.
        /// </summary>
        /// <param name="navigationLink">The navigation link read from the payload to apply.</param>
        /// <param name="entityResourceSet">The resource set into which the entity belongs to.</param>
        /// <param name="entityResourceType">The type of the entity to apply the properties to.</param>
        /// <param name="navigationProperty">The navigation property which coresponds with the navigation link.</param>
        /// <param name="entityResource">The entity resource to apply the properties to.</param>
        private void ApplyNavigationProperty(
            ODataNavigationLink navigationLink,
            ResourceSetWrapper entityResourceSet,
            ResourceType entityResourceType,
            ResourceProperty navigationProperty,
            object entityResource)
        {
            Debug.Assert(navigationLink != null, "navigationLink != null");
            Debug.Assert(entityResourceSet != null, "entityResourceSet != null");
            Debug.Assert(entityResourceType != null, "entityResourceType != null");
            Debug.Assert(entityResourceType.ResourceTypeKind == ResourceTypeKind.EntityType, "Only entity types can be specified for entities.");
            Debug.Assert(navigationProperty != null && navigationProperty.TypeKind == ResourceTypeKind.EntityType, "navigationProperty != null && navigationProperty.TypeKind == ResourceTypeKind.EntityType");
            Debug.Assert(navigationLink.Name == navigationProperty.Name, "The navigationProperty must have the same name as the navigationLink to apply.");
            Debug.Assert(entityResource != null, "entityResource != null");

            ResourceSetWrapper targetResourceSet = null;

            // Get the target resource set for the navigation property, this also causes validation of the resource set and thus migth fail.
            // WCF DS Used to do this in ATOM only if the link was expanded, which was a security issue we decided to fix, so now we do it always.
            targetResourceSet = this.GetNavigationPropertyTargetResourceSet(entityResourceSet, entityResourceType, navigationProperty);

            ODataNavigationLinkAnnotation navigationLinkAnnotation = navigationLink.GetAnnotation <ODataNavigationLinkAnnotation>();

            Debug.Assert(navigationLinkAnnotation != null, "navigationLinkAnnotation != null");
            Debug.Assert(navigationLinkAnnotation.Count > 0, "Each navigation link must have at least one child in request.");
            Debug.Assert(navigationLink.IsCollection.HasValue, "We should know the cardinality of the navigation link by now.");

            // We have to allow IsCollection=false for ResourceSetReference properties as well.
            Debug.Assert(
                navigationLink.IsCollection == true || (navigationLinkAnnotation.Count == 1),
                "If the navigation link is a singleton, then there must be exactly one child in it and the property must be a singleton as well.");
            Debug.Assert(
                navigationLink.IsCollection == false || (navigationProperty.Kind == ResourcePropertyKind.ResourceSetReference),
                "If the navigation link is a collection, then the property must be a collection as well.");

            // Just loop through the navigation link content
            // Note that if the navigation link is a singleton it must have just one item in it, so it's OK to loop anyway.
            foreach (ODataItem childItem in navigationLinkAnnotation)
            {
                ODataEntityReferenceLink entityReferenceLink = childItem as ODataEntityReferenceLink;
                if (entityReferenceLink != null)
                {
                    this.ApplyEntityReferenceLinkInNavigationProperty(navigationProperty, entityResource, entityReferenceLink);
                    continue;
                }

                ODataFeed feed = childItem as ODataFeed;
                if (feed != null)
                {
                    this.ApplyFeedInNavigationProperty(navigationProperty, targetResourceSet, entityResource, feed);
                    continue;
                }

                // It must be entry by now.
                ODataEntry entry = (ODataEntry)childItem;
                this.ApplyEntryInNavigationProperty(navigationProperty, targetResourceSet, entityResource, entry);
            }
        }
Пример #3
0
        internal static ODataItem ReadEntryOrFeed(ODataReader odataReader, ODataDeserializerContext readContext)
        {
            ODataItem         topLevelItem = null;
            Stack <ODataItem> itemsStack   = new Stack <ODataItem>();

            while (odataReader.Read())
            {
                switch (odataReader.State)
                {
                case ODataReaderState.EntryStart:
                    ODataEntry           entry           = (ODataEntry)odataReader.Item;
                    ODataEntryAnnotation entryAnnotation = null;
                    if (entry != null)
                    {
                        entryAnnotation = new ODataEntryAnnotation();
                        entry.SetAnnotation(entryAnnotation);
                    }

                    if (itemsStack.Count == 0)
                    {
                        Contract.Assert(entry != null, "The top-level entry can never be null.");
                        topLevelItem = entry;
                    }
                    else
                    {
                        ODataItem parentItem = itemsStack.Peek();
                        ODataFeed parentFeed = parentItem as ODataFeed;
                        if (parentFeed != null)
                        {
                            ODataFeedAnnotation parentFeedAnnotation = parentFeed.GetAnnotation <ODataFeedAnnotation>();
                            Contract.Assert(parentFeedAnnotation != null, "Every feed we added to the stack should have the feed annotation on it.");
                            parentFeedAnnotation.Add(entry);
                        }
                        else
                        {
                            ODataNavigationLink           parentNavigationLink           = (ODataNavigationLink)parentItem;
                            ODataNavigationLinkAnnotation parentNavigationLinkAnnotation = parentNavigationLink.GetAnnotation <ODataNavigationLinkAnnotation>();
                            Contract.Assert(parentNavigationLinkAnnotation != null, "Every navigation link we added to the stack should have the navigation link annotation on it.");

                            Contract.Assert(parentNavigationLink.IsCollection == false, "Only singleton navigation properties can contain entry as their child.");
                            Contract.Assert(parentNavigationLinkAnnotation.Count == 0, "Each navigation property can contain only one entry as its direct child.");
                            parentNavigationLinkAnnotation.Add(entry);
                        }
                    }
                    itemsStack.Push(entry);
                    RecurseEnter(readContext);
                    break;

                case ODataReaderState.EntryEnd:
                    Contract.Assert(itemsStack.Count > 0 && itemsStack.Peek() == odataReader.Item, "The entry which is ending should be on the top of the items stack.");
                    itemsStack.Pop();
                    RecurseLeave(readContext);
                    break;

                case ODataReaderState.NavigationLinkStart:
                    ODataNavigationLink navigationLink = (ODataNavigationLink)odataReader.Item;
                    Contract.Assert(navigationLink != null, "Navigation link should never be null.");

                    navigationLink.SetAnnotation(new ODataNavigationLinkAnnotation());
                    Contract.Assert(itemsStack.Count > 0, "Navigation link can't appear as top-level item.");
                    {
                        ODataEntry           parentEntry           = (ODataEntry)itemsStack.Peek();
                        ODataEntryAnnotation parentEntryAnnotation = parentEntry.GetAnnotation <ODataEntryAnnotation>();
                        Contract.Assert(parentEntryAnnotation != null, "Every entry we added to the stack should have the entry annotation on it.");
                        parentEntryAnnotation.Add(navigationLink);
                    }

                    itemsStack.Push(navigationLink);
                    RecurseEnter(readContext);
                    break;

                case ODataReaderState.NavigationLinkEnd:
                    Contract.Assert(itemsStack.Count > 0 && itemsStack.Peek() == odataReader.Item, "The navigation link which is ending should be on the top of the items stack.");
                    itemsStack.Pop();
                    RecurseLeave(readContext);
                    break;

                case ODataReaderState.FeedStart:
                    ODataFeed feed = (ODataFeed)odataReader.Item;
                    Contract.Assert(feed != null, "Feed should never be null.");

                    feed.SetAnnotation(new ODataFeedAnnotation());
                    if (itemsStack.Count > 0)
                    {
                        ODataNavigationLink parentNavigationLink = (ODataNavigationLink)itemsStack.Peek();
                        Contract.Assert(parentNavigationLink != null, "this has to be an inner feed. inner feeds always have a navigation link.");
                        ODataNavigationLinkAnnotation parentNavigationLinkAnnotation = parentNavigationLink.GetAnnotation <ODataNavigationLinkAnnotation>();
                        Contract.Assert(parentNavigationLinkAnnotation != null, "Every navigation link we added to the stack should have the navigation link annotation on it.");

                        Contract.Assert(parentNavigationLink.IsCollection == true, "Only collection navigation properties can contain feed as their child.");
                        parentNavigationLinkAnnotation.Add(feed);
                    }
                    else
                    {
                        topLevelItem = feed;
                    }

                    itemsStack.Push(feed);
                    RecurseEnter(readContext);
                    break;

                case ODataReaderState.FeedEnd:
                    Contract.Assert(itemsStack.Count > 0 && itemsStack.Peek() == odataReader.Item, "The feed which is ending should be on the top of the items stack.");
                    itemsStack.Pop();
                    RecurseLeave(readContext);
                    break;

                case ODataReaderState.EntityReferenceLink:
                    ODataEntityReferenceLink entityReferenceLink = (ODataEntityReferenceLink)odataReader.Item;
                    Contract.Assert(entityReferenceLink != null, "Entity reference link should never be null.");

                    Contract.Assert(itemsStack.Count > 0, "Entity reference link should never be reported as top-level item.");
                    {
                        ODataNavigationLink           parentNavigationLink           = (ODataNavigationLink)itemsStack.Peek();
                        ODataNavigationLinkAnnotation parentNavigationLinkAnnotation = parentNavigationLink.GetAnnotation <ODataNavigationLinkAnnotation>();
                        Contract.Assert(parentNavigationLinkAnnotation != null, "Every navigation link we added to the stack should have the navigation link annotation on it.");

                        parentNavigationLinkAnnotation.Add(entityReferenceLink);
                    }

                    break;

                default:
                    Contract.Assert(false, "We should never get here, it means the ODataReader reported a wrong state.");
                    break;
                }
            }

            Contract.Assert(odataReader.State == ODataReaderState.Completed, "We should have consumed all of the input by now.");
            Contract.Assert(topLevelItem != null, "A top level entry or feed should have been read by now.");
            return(topLevelItem);
        }
Пример #4
0
        /// <summary>
        /// Reads an entry from the <paramref name="odataReader"/> and all it's children including expanded entries and feeds.
        /// </summary>
        /// <param name="odataReader">The ODataReader to read from.</param>
        /// <param name="topLevelSegmentInfo">The segment info for the top-level entry to read.</param>
        /// <returns>The <see cref="ODataEntry"/> with annotations which store the navigation links and their expanded values.</returns>
        private ODataEntry ReadEntry(ODataReader odataReader, SegmentInfo topLevelSegmentInfo)
        {
            Debug.Assert(odataReader != null, "odataReader != null");
            Debug.Assert(odataReader.State == ODataReaderState.Start, "The ODataReader must not have been used yet.");
            Debug.Assert(topLevelSegmentInfo != null, "topLevelSegmentInfo != null");

            ODataEntry        topLevelEntry = null;
            Stack <ODataItem> itemsStack    = new Stack <ODataItem>();

            while (odataReader.Read())
            {
                // Don't let the item stack grow larger than we can process later. Also lets us to fail and report the recursion depth limit error before ODL does.
                if (itemsStack.Count >= RecursionLimit)
                {
                    throw DataServiceException.CreateDeepRecursion(RecursionLimit);
                }

                switch (odataReader.State)
                {
                case ODataReaderState.EntryStart:
                    ODataEntry           entry           = (ODataEntry)odataReader.Item;
                    ODataEntryAnnotation entryAnnotation = null;
                    if (entry != null)
                    {
                        entryAnnotation = new ODataEntryAnnotation();
                        entry.SetAnnotation(entryAnnotation);
                    }

                    if (itemsStack.Count == 0)
                    {
                        Debug.Assert(entry != null, "The top-level entry can never be null.");
                        topLevelEntry = entry;

                        // For top-level entry, create the entry resource here.
                        // This is needed since the creation of the resource may fail (especially if this is an update in which case
                        // we evaluate the URL query, which may return no results and thus we would fail with 404)
                        // and we need to report that failure rather then potential other failures caused by the properties in the entry in question.
                        this.CreateEntityResource(topLevelSegmentInfo, entry, entryAnnotation, /*topLevel*/ true);
                    }
                    else
                    {
                        ODataItem parentItem = itemsStack.Peek();
                        ODataFeed parentFeed = parentItem as ODataFeed;
                        if (parentFeed != null)
                        {
                            ODataFeedAnnotation parentFeedAnnotation = parentFeed.GetAnnotation <ODataFeedAnnotation>();
                            Debug.Assert(parentFeedAnnotation != null, "Every feed we added to the stack should have the feed annotation on it.");
                            parentFeedAnnotation.Add(entry);
                        }
                        else
                        {
                            ODataNavigationLink           parentNavigationLink           = (ODataNavigationLink)parentItem;
                            ODataNavigationLinkAnnotation parentNavigationLinkAnnotation = parentNavigationLink.GetAnnotation <ODataNavigationLinkAnnotation>();
                            Debug.Assert(parentNavigationLinkAnnotation != null, "Every navigation link we added to the stack should have the navigation link annotation on it.");

                            Debug.Assert(parentNavigationLink.IsCollection == false, "Only singleton navigation properties can contain entry as their child.");
                            Debug.Assert(parentNavigationLinkAnnotation.Count == 0, "Each navigation property can contain only one entry as its direct child.");
                            parentNavigationLinkAnnotation.Add(entry);
                        }
                    }

                    itemsStack.Push(entry);
                    break;

                case ODataReaderState.EntryEnd:
                    Debug.Assert(itemsStack.Count > 0 && itemsStack.Peek() == odataReader.Item, "The entry which is ending should be on the top of the items stack.");
                    itemsStack.Pop();
                    break;

                case ODataReaderState.NavigationLinkStart:
                    ODataNavigationLink navigationLink = (ODataNavigationLink)odataReader.Item;
                    Debug.Assert(navigationLink != null, "Navigation link should never be null.");

                    navigationLink.SetAnnotation(new ODataNavigationLinkAnnotation());
                    Debug.Assert(itemsStack.Count > 0, "Navigation link can't appear as top-level item.");
                    {
                        ODataEntry           parentEntry           = (ODataEntry)itemsStack.Peek();
                        ODataEntryAnnotation parentEntryAnnotation = parentEntry.GetAnnotation <ODataEntryAnnotation>();
                        Debug.Assert(parentEntryAnnotation != null, "Every entry we added to the stack should have the navigation link annotation on it.");
                        parentEntryAnnotation.Add(navigationLink);
                    }

                    itemsStack.Push(navigationLink);
                    break;

                case ODataReaderState.NavigationLinkEnd:
                    Debug.Assert(itemsStack.Count > 0 && itemsStack.Peek() == odataReader.Item, "The navigation link which is ending should be on the top of the items stack.");
                    itemsStack.Pop();
                    break;

                case ODataReaderState.FeedStart:
                    ODataFeed feed = (ODataFeed)odataReader.Item;
                    Debug.Assert(feed != null, "Feed should never be null.");

                    feed.SetAnnotation(new ODataFeedAnnotation());
                    Debug.Assert(itemsStack.Count > 0, "Since we always start reading entry, we should never get a feed as the top-level item.");
                    {
                        ODataNavigationLink           parentNavigationLink           = (ODataNavigationLink)itemsStack.Peek();
                        ODataNavigationLinkAnnotation parentNavigationLinkAnnotation = parentNavigationLink.GetAnnotation <ODataNavigationLinkAnnotation>();
                        Debug.Assert(parentNavigationLinkAnnotation != null, "Every navigation link we added to the stack should have the navigation link annotation on it.");

                        Debug.Assert(parentNavigationLink.IsCollection == true, "Only collection navigation properties can contain feed as their child.");
                        parentNavigationLinkAnnotation.Add(feed);
                    }

                    itemsStack.Push(feed);
                    break;

                case ODataReaderState.FeedEnd:
                    Debug.Assert(itemsStack.Count > 0 && itemsStack.Peek() == odataReader.Item, "The feed which is ending should be on the top of the items stack.");
                    itemsStack.Pop();
                    break;

                case ODataReaderState.EntityReferenceLink:
                    ODataEntityReferenceLink entityReferenceLink = (ODataEntityReferenceLink)odataReader.Item;
                    Debug.Assert(entityReferenceLink != null, "Entity reference link should never be null.");

                    Debug.Assert(itemsStack.Count > 0, "Entity reference link should never be reported as top-level item.");
                    {
                        ODataNavigationLink           parentNavigationLink           = (ODataNavigationLink)itemsStack.Peek();
                        ODataNavigationLinkAnnotation parentNavigationLinkAnnotation = parentNavigationLink.GetAnnotation <ODataNavigationLinkAnnotation>();
                        Debug.Assert(parentNavigationLinkAnnotation != null, "Every navigation link we added to the stack should have the navigation link annotation on it.");

                        parentNavigationLinkAnnotation.Add(entityReferenceLink);
                    }

                    break;

                default:
                    Debug.Assert(false, "We should never get here, it means the ODataReader reported a wrong state.");
                    break;
                }
            }

            Debug.Assert(odataReader.State == ODataReaderState.Completed, "We should have consumed all of the input by now.");
            Debug.Assert(topLevelEntry != null, "A top level entry should have been read by now.");
            return(topLevelEntry);
        }