/// <summary>
        /// Deserializes the navigation property from <paramref name="navigationLinkWrapper"/> into <paramref name="entityResource"/>.
        /// </summary>
        /// <param name="entityResource">The object into which the navigation property should be read.</param>
        /// <param name="navigationLinkWrapper">The navigation link.</param>
        /// <param name="entityType">The entity type of the entity resource.</param>
        /// <param name="readContext">The deserializer context.</param>
        public virtual void ApplyNavigationProperty(object entityResource, ODataNavigationLinkWithItems navigationLinkWrapper,
                                                    IEdmEntityTypeReference entityType, ODataDeserializerContext readContext)
        {
            if (navigationLinkWrapper == null)
            {
                throw Error.ArgumentNull("navigationLinkWrapper");
            }

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

            IEdmNavigationProperty navigationProperty = entityType.FindProperty(navigationLinkWrapper.NavigationLink.Name) as IEdmNavigationProperty;

            if (navigationProperty == null)
            {
                throw new ODataException(
                          Error.Format(SRResources.NavigationPropertyNotfound, navigationLinkWrapper.NavigationLink.Name, entityType.FullName()));
            }

            foreach (ODataItemBase childItem in navigationLinkWrapper.NestedItems)
            {
                ODataEntityReferenceLinkBase entityReferenceLink = childItem as ODataEntityReferenceLinkBase;
                if (entityReferenceLink != null)
                {
                    // ignore links.
                    continue;
                }

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

                // It must be entry by now.
                ODataEntryWithNavigationLinks entry = (ODataEntryWithNavigationLinks)childItem;
                if (entry != null)
                {
                    ApplyEntryInNavigationProperty(navigationProperty, entityResource, entry, readContext);
                }
            }
        }
        /// <summary>
        /// Reads an ODataFeed or an ODataItem from the reader.
        /// </summary>
        /// <param name="reader">The OData reader to read from.</param>
        /// <returns>The read feed or entry.</returns>
        public static ODataItemBase ReadEntryOrFeed(ODataReader reader)
        {
            if (reader == null)
            {
                throw Error.ArgumentNull("odataReader");
            }

            ODataItemBase topLevelItem = null;
            Stack<ODataItemBase> itemsStack = new Stack<ODataItemBase>();

            while (reader.Read())
            {
                switch (reader.State)
                {
                    case ODataReaderState.EntryStart:
                        ODataEntry entry = (ODataEntry)reader.Item;
                        ODataEntryWithNavigationLinks entryWrapper = null;
                        if (entry != null)
                        {
                            entryWrapper = new ODataEntryWithNavigationLinks(entry);
                        }

                        if (itemsStack.Count == 0)
                        {
                            Contract.Assert(entry != null, "The top-level entry can never be null.");
                            topLevelItem = entryWrapper;
                        }
                        else
                        {
                            ODataItemBase parentItem = itemsStack.Peek();
                            ODataFeedWithEntries parentFeed = parentItem as ODataFeedWithEntries;
                            if (parentFeed != null)
                            {
                                parentFeed.Entries.Add(entryWrapper);
                            }
                            else
                            {
                                ODataNavigationLinkWithItems parentNavigationLink = (ODataNavigationLinkWithItems)parentItem;
                                Contract.Assert(parentNavigationLink.NavigationLink.IsCollection == false, "Only singleton navigation properties can contain entry as their child.");
                                Contract.Assert(parentNavigationLink.NestedItems.Count == 0, "Each navigation property can contain only one entry as its direct child.");
                                parentNavigationLink.NestedItems.Add(entryWrapper);
                            }
                        }
                        itemsStack.Push(entryWrapper);
                        break;

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

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

                        ODataNavigationLinkWithItems navigationLinkWrapper = new ODataNavigationLinkWithItems(navigationLink);
                        Contract.Assert(itemsStack.Count > 0, "Navigation link can't appear as top-level item.");
                        {
                            ODataEntryWithNavigationLinks parentEntry = (ODataEntryWithNavigationLinks)itemsStack.Peek();
                            parentEntry.NavigationLinks.Add(navigationLinkWrapper);
                        }

                        itemsStack.Push(navigationLinkWrapper);
                        break;

                    case ODataReaderState.NavigationLinkEnd:
                        Contract.Assert(itemsStack.Count > 0 && itemsStack.Peek().Item == reader.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)reader.Item;
                        Contract.Assert(feed != null, "Feed should never be null.");

                        ODataFeedWithEntries feedWrapper = new ODataFeedWithEntries(feed);
                        if (itemsStack.Count > 0)
                        {
                            ODataNavigationLinkWithItems parentNavigationLink = (ODataNavigationLinkWithItems)itemsStack.Peek();
                            Contract.Assert(parentNavigationLink != null, "this has to be an inner feed. inner feeds always have a navigation link.");
                            Contract.Assert(parentNavigationLink.NavigationLink.IsCollection == true, "Only collection navigation properties can contain feed as their child.");
                            parentNavigationLink.NestedItems.Add(feedWrapper);
                        }
                        else
                        {
                            topLevelItem = feedWrapper;
                        }

                        itemsStack.Push(feedWrapper);
                        break;

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

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

                        Contract.Assert(itemsStack.Count > 0, "Entity reference link should never be reported as top-level item.");
                        {
                            ODataNavigationLinkWithItems parentNavigationLink = (ODataNavigationLinkWithItems)itemsStack.Peek();
                            parentNavigationLink.NestedItems.Add(entityReferenceLinkWrapper);
                        }

                        break;

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

            Contract.Assert(reader.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;
        }
Example #3
0
        /// <summary>
        /// Deserializes the nested property from <paramref name="resourceInfoWrapper"/> into <paramref name="resource"/>.
        /// </summary>
        /// <param name="resource">The object into which the nested property should be read.</param>
        /// <param name="resourceInfoWrapper">The nested resource info.</param>
        /// <param name="structuredType">The type of the resource.</param>
        /// <param name="readContext">The deserializer context.</param>
        public virtual void ApplyNestedProperty(object resource, ODataNestedResourceInfoWrapper resourceInfoWrapper,
                                                IEdmStructuredTypeReference structuredType, ODataDeserializerContext readContext)
        {
            if (resource == null)
            {
                throw Error.ArgumentNull("resource");
            }

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

            IEdmProperty edmProperty = structuredType.FindProperty(resourceInfoWrapper.NestedResourceInfo.Name);

            if (edmProperty == null)
            {
                if (!structuredType.IsOpen())
                {
                    throw new ODataException(
                              Error.Format(SRResources.NestedPropertyNotfound, resourceInfoWrapper.NestedResourceInfo.Name,
                                           structuredType.FullName()));
                }
            }

            foreach (ODataItemBase childItem in resourceInfoWrapper.NestedItems)
            {
                // it maybe null.
                if (childItem == null)
                {
                    if (edmProperty == null)
                    {
                        // for the dynamic, OData.net has a bug. see https://github.com/OData/odata.net/issues/977
                        ApplyDynamicResourceInNestedProperty(resourceInfoWrapper.NestedResourceInfo.Name, resource,
                                                             structuredType, null, readContext);
                    }
                    else
                    {
                        ApplyResourceInNestedProperty(edmProperty, resource, null, readContext);
                    }
                }

                ODataEntityReferenceLinkBase entityReferenceLink = childItem as ODataEntityReferenceLinkBase;
                if (entityReferenceLink != null)
                {
                    // ignore entity reference links.
                    continue;
                }

                ODataResourceSetWrapper resourceSetWrapper = childItem as ODataResourceSetWrapper;
                if (resourceSetWrapper != null)
                {
                    if (edmProperty == null)
                    {
                        ApplyDynamicResourceSetInNestedProperty(resourceInfoWrapper.NestedResourceInfo.Name,
                                                                resource, structuredType, resourceSetWrapper, readContext);
                    }
                    else
                    {
                        ApplyResourceSetInNestedProperty(edmProperty, resource, resourceSetWrapper, readContext);
                    }

                    continue;
                }

                // It must be resource by now.
                ODataResourceWrapper resourceWrapper = (ODataResourceWrapper)childItem;
                if (resourceWrapper != null)
                {
                    if (edmProperty == null)
                    {
                        ApplyDynamicResourceInNestedProperty(resourceInfoWrapper.NestedResourceInfo.Name, resource,
                                                             structuredType, resourceWrapper, readContext);
                    }
                    else
                    {
                        ApplyResourceInNestedProperty(edmProperty, resource, resourceWrapper, readContext);
                    }
                }
            }
        }
        /// <summary>
        /// Reads an ODataFeed or an ODataItem from the reader.
        /// </summary>
        /// <param name="reader">The OData reader to read from.</param>
        /// <returns>The read feed or entry.</returns>
        public static ODataItemBase ReadEntryOrFeed(ODataReader reader)
        {
            if (reader == null)
            {
                throw Error.ArgumentNull("odataReader");
            }

            ODataItemBase         topLevelItem = null;
            Stack <ODataItemBase> itemsStack   = new Stack <ODataItemBase>();

            while (reader.Read())
            {
                switch (reader.State)
                {
                case ODataReaderState.EntryStart:
                    ODataEntry entry = (ODataEntry)reader.Item;
                    ODataEntryWithNavigationLinks entryWrapper = null;
                    if (entry != null)
                    {
                        entryWrapper = new ODataEntryWithNavigationLinks(entry);
                    }

                    if (itemsStack.Count == 0)
                    {
                        Contract.Assert(entry != null, "The top-level entry can never be null.");
                        topLevelItem = entryWrapper;
                    }
                    else
                    {
                        ODataItemBase        parentItem = itemsStack.Peek();
                        ODataFeedWithEntries parentFeed = parentItem as ODataFeedWithEntries;
                        if (parentFeed != null)
                        {
                            parentFeed.Entries.Add(entryWrapper);
                        }
                        else
                        {
                            ODataNavigationLinkWithItems parentNavigationLink = (ODataNavigationLinkWithItems)parentItem;
                            Contract.Assert(parentNavigationLink.NavigationLink.IsCollection == false, "Only singleton navigation properties can contain entry as their child.");
                            Contract.Assert(parentNavigationLink.NestedItems.Count == 0, "Each navigation property can contain only one entry as its direct child.");
                            parentNavigationLink.NestedItems.Add(entryWrapper);
                        }
                    }
                    itemsStack.Push(entryWrapper);
                    break;

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

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

                    ODataNavigationLinkWithItems navigationLinkWrapper = new ODataNavigationLinkWithItems(navigationLink);
                    Contract.Assert(itemsStack.Count > 0, "Navigation link can't appear as top-level item.");
                    {
                        ODataEntryWithNavigationLinks parentEntry = (ODataEntryWithNavigationLinks)itemsStack.Peek();
                        parentEntry.NavigationLinks.Add(navigationLinkWrapper);
                    }

                    itemsStack.Push(navigationLinkWrapper);
                    break;

                case ODataReaderState.NavigationLinkEnd:
                    Contract.Assert(itemsStack.Count > 0 && itemsStack.Peek().Item == reader.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)reader.Item;
                    Contract.Assert(feed != null, "Feed should never be null.");

                    ODataFeedWithEntries feedWrapper = new ODataFeedWithEntries(feed);
                    if (itemsStack.Count > 0)
                    {
                        ODataNavigationLinkWithItems parentNavigationLink = (ODataNavigationLinkWithItems)itemsStack.Peek();
                        Contract.Assert(parentNavigationLink != null, "this has to be an inner feed. inner feeds always have a navigation link.");
                        Contract.Assert(parentNavigationLink.NavigationLink.IsCollection == true, "Only collection navigation properties can contain feed as their child.");
                        parentNavigationLink.NestedItems.Add(feedWrapper);
                    }
                    else
                    {
                        topLevelItem = feedWrapper;
                    }

                    itemsStack.Push(feedWrapper);
                    break;

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

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

                    Contract.Assert(itemsStack.Count > 0, "Entity reference link should never be reported as top-level item.");
                    {
                        ODataNavigationLinkWithItems parentNavigationLink = (ODataNavigationLinkWithItems)itemsStack.Peek();
                        parentNavigationLink.NestedItems.Add(entityReferenceLinkWrapper);
                    }

                    break;

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

            Contract.Assert(reader.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);
        }
        /// <summary>
        /// Reads a <see cref="ODataResource"/> or <see cref="ODataResourceSet"/> object.
        /// </summary>
        /// <param name="reader">The OData reader to read from.</param>
        /// <returns>The read resource or resource set.</returns>
        public static ODataItemBase ReadResourceOrResourceSet(this ODataReader reader)
        {
            if (reader == null)
            {
                throw Error.ArgumentNull("reader");
            }

            ODataItemBase         topLevelItem = null;
            Stack <ODataItemBase> itemsStack   = new Stack <ODataItemBase>();

            while (reader.Read())
            {
                switch (reader.State)
                {
                case ODataReaderState.ResourceStart:
                    ODataResource        resource        = (ODataResource)reader.Item;
                    ODataResourceWrapper resourceWrapper = null;
                    if (resource != null)
                    {
                        resourceWrapper = new ODataResourceWrapper(resource);
                    }

                    if (itemsStack.Count == 0)
                    {
                        Contract.Assert(resource != null, "The top-level resource can never be null.");
                        topLevelItem = resourceWrapper;
                    }
                    else
                    {
                        ODataItemBase           parentItem        = itemsStack.Peek();
                        ODataResourceSetWrapper parentResourceSet = parentItem as ODataResourceSetWrapper;
                        if (parentResourceSet != null)
                        {
                            parentResourceSet.Resources.Add(resourceWrapper);
                        }
                        else
                        {
                            ODataNestedResourceInfoWrapper parentNestedResource = (ODataNestedResourceInfoWrapper)parentItem;
                            Contract.Assert(parentNestedResource.NestedResourceInfo.IsCollection == false, "Only singleton nested properties can contain resource as their child.");
                            Contract.Assert(parentNestedResource.NestedItems.Count == 0, "Each nested property can contain only one resource as its direct child.");
                            parentNestedResource.NestedItems.Add(resourceWrapper);
                        }
                    }

                    itemsStack.Push(resourceWrapper);
                    break;

                case ODataReaderState.ResourceEnd:
                    Contract.Assert(
                        itemsStack.Count > 0 && (reader.Item == null || itemsStack.Peek().Item == reader.Item),
                        "The resource which is ending should be on the top of the items stack.");
                    itemsStack.Pop();
                    break;

                case ODataReaderState.NestedResourceInfoStart:
                    ODataNestedResourceInfo nestedResourceInfo = (ODataNestedResourceInfo)reader.Item;
                    Contract.Assert(nestedResourceInfo != null, "nested resource info should never be null.");

                    ODataNestedResourceInfoWrapper nestedResourceInfoWrapper = new ODataNestedResourceInfoWrapper(nestedResourceInfo);
                    Contract.Assert(itemsStack.Count > 0, "nested resource info can't appear as top-level item.");
                    {
                        ODataResourceWrapper parentResource = (ODataResourceWrapper)itemsStack.Peek();
                        parentResource.NestedResourceInfos.Add(nestedResourceInfoWrapper);
                    }

                    itemsStack.Push(nestedResourceInfoWrapper);
                    break;

                case ODataReaderState.NestedResourceInfoEnd:
                    Contract.Assert(itemsStack.Count > 0 && itemsStack.Peek().Item == reader.Item,
                                    "The nested resource info which is ending should be on the top of the items stack.");
                    itemsStack.Pop();
                    break;

                case ODataReaderState.ResourceSetStart:
                    ODataResourceSet resourceSet = (ODataResourceSet)reader.Item;
                    Contract.Assert(resourceSet != null, "ResourceSet should never be null.");

                    ODataResourceSetWrapper resourceSetWrapper = new ODataResourceSetWrapper(resourceSet);
                    if (itemsStack.Count > 0)
                    {
                        ODataNestedResourceInfoWrapper parentNestedResourceInfo = (ODataNestedResourceInfoWrapper)itemsStack.Peek();
                        Contract.Assert(parentNestedResourceInfo != null, "this has to be an inner resource set. inner resource sets always have a nested resource info.");
                        Contract.Assert(parentNestedResourceInfo.NestedResourceInfo.IsCollection == true, "Only collection nested properties can contain resource set as their child.");
                        parentNestedResourceInfo.NestedItems.Add(resourceSetWrapper);
                    }
                    else
                    {
                        topLevelItem = resourceSetWrapper;
                    }

                    itemsStack.Push(resourceSetWrapper);
                    break;

                case ODataReaderState.ResourceSetEnd:
                    Contract.Assert(itemsStack.Count > 0 && itemsStack.Peek().Item == reader.Item, "The resource set which is ending should be on the top of the items stack.");
                    itemsStack.Pop();
                    break;

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

                    Contract.Assert(itemsStack.Count > 0, "Entity reference link should never be reported as top-level item.");
                    {
                        ODataNestedResourceInfoWrapper parentNavigationLink = (ODataNestedResourceInfoWrapper)itemsStack.Peek();
                        parentNavigationLink.NestedItems.Add(entityReferenceLinkWrapper);
                    }

                    break;

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

            Contract.Assert(reader.State == ODataReaderState.Completed, "We should have consumed all of the input by now.");
            Contract.Assert(topLevelItem != null, "A top level resource or resource set should have been read by now.");
            return(topLevelItem);
        }