/// <summary> /// Creates a navigation link info for a projected navigation link that is missing from the payload. /// </summary> /// <param name="navigationProperty">The navigation property for which the link will be reported.</param> /// <returns>The navigation link info created.</returns> internal static ODataJsonLightReaderNavigationLinkInfo CreateProjectedNavigationLinkInfo(IEdmNavigationProperty navigationProperty) { Debug.Assert(navigationProperty != null, "navigationProperty != null"); ODataNavigationLink navigationLink = new ODataNavigationLink { Name = navigationProperty.Name, IsCollection = navigationProperty.Type.IsCollection() }; ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo = new ODataJsonLightReaderNavigationLinkInfo(navigationLink, navigationProperty, /*isExpanded*/ false); return(navigationLinkInfo); }
/// <summary> /// Creates a navigation link info for an expanded entry link. /// </summary> /// <param name="navigationLink">The navigation link to report.</param> /// <param name="navigationProperty">The navigation property for which the link will be reported.</param> /// <returns>The navigation link info created.</returns> internal static ODataJsonLightReaderNavigationLinkInfo CreateExpandedEntryLinkInfo( ODataNavigationLink navigationLink, IEdmNavigationProperty navigationProperty) { Debug.Assert(navigationLink != null, "navigationLink != null"); Debug.Assert(navigationLink.IsCollection == false, "Expanded entry can only be reported for a singleton navigation link."); ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo = new ODataJsonLightReaderNavigationLinkInfo(navigationLink, navigationProperty, /*isExpanded*/ true); return(navigationLinkInfo); }
/// <summary> /// Creates a navigation link info for an expanded feed link. /// </summary> /// <param name="navigationLink">The navigation link to report.</param> /// <param name="navigationProperty">The navigation property for which the link will be reported.</param> /// <param name="expandedFeed">The expanded feed for the navigation link to report.</param> /// <returns>The navigation link info created.</returns> internal static ODataJsonLightReaderNavigationLinkInfo CreateExpandedFeedLinkInfo( ODataNavigationLink navigationLink, IEdmNavigationProperty navigationProperty, ODataFeed expandedFeed) { Debug.Assert(navigationLink != null, "navigationLink != null"); Debug.Assert(navigationLink.IsCollection == true, "Expanded feeds can only be reported for collection navigation links."); Debug.Assert(expandedFeed != null, "expandedFeed != null"); ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo = new ODataJsonLightReaderNavigationLinkInfo(navigationLink, navigationProperty, /*isExpanded*/ true); navigationLinkInfo.expandedFeed = expandedFeed; return(navigationLinkInfo); }
/// <summary> /// Creates a navigation link info for a collection of entity reference links. /// </summary> /// <param name="navigationLink">The navigation link to report.</param> /// <param name="navigationProperty">The navigation property for which the link will be reported.</param> /// <param name="entityReferenceLinks">The entity reference links for the navigation link to report.</param> /// <param name="isExpanded">true if the navigation link is expanded.</param> /// <returns>The navigation link info created.</returns> internal static ODataJsonLightReaderNavigationLinkInfo CreateCollectionEntityReferenceLinksInfo( ODataNavigationLink navigationLink, IEdmNavigationProperty navigationProperty, LinkedList <ODataEntityReferenceLink> entityReferenceLinks, bool isExpanded) { Debug.Assert(navigationLink != null, "navigationLink != null"); Debug.Assert(navigationLink.IsCollection == true, "Collection entity reference can only be reported for a collection navigation links."); Debug.Assert(navigationProperty != null, "navigationProperty != null"); Debug.Assert(entityReferenceLinks == null || entityReferenceLinks.Count > 0, "entityReferenceLinks == null || entityReferenceLinks.Count > 0"); ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo = new ODataJsonLightReaderNavigationLinkInfo(navigationLink, navigationProperty, isExpanded); navigationLinkInfo.entityReferenceLinks = entityReferenceLinks; return(navigationLinkInfo); }
/// <summary> /// Creates a navigation link info for a singleton entity reference link. /// </summary> /// <param name="navigationLink">The navigation link to report.</param> /// <param name="navigationProperty">The navigation property for which the link will be reported.</param> /// <param name="entityReferenceLink">The entity reference link for the navigation link to report.</param> /// <param name="isExpanded">true if the navigation link is expanded.</param> /// <returns>The navigation link info created.</returns> internal static ODataJsonLightReaderNavigationLinkInfo CreateSingletonEntityReferenceLinkInfo( ODataNavigationLink navigationLink, IEdmNavigationProperty navigationProperty, ODataEntityReferenceLink entityReferenceLink, bool isExpanded) { Debug.Assert(navigationLink != null, "navigationLink != null"); Debug.Assert(navigationLink.IsCollection == false, "Singleton entity reference can only be reported for a singleton navigation links."); Debug.Assert(navigationProperty != null, "navigationProperty != null"); ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo = new ODataJsonLightReaderNavigationLinkInfo(navigationLink, navigationProperty, isExpanded); if (entityReferenceLink != null) { navigationLinkInfo.entityReferenceLinks = new LinkedList <ODataEntityReferenceLink>(); navigationLinkInfo.entityReferenceLinks.AddFirst(entityReferenceLink); } return(navigationLinkInfo); }
/// <summary> /// Reads any next link annotation immediately after the end of a feed. /// </summary> /// <param name="feed">The feed being read.</param> /// <param name="expandedNavigationLinkInfo">The information about the expanded link. This must be non-null if we're reading an expanded feed, and must be null if we're reading a top-level feed.</param> /// <param name="duplicatePropertyNamesChecker">The top-level duplicate property names checker, if we're reading a top-level feed.</param> internal void ReadNextLinkAnnotationAtFeedEnd( ODataFeedBase feed, ODataJsonLightReaderNavigationLinkInfo expandedNavigationLinkInfo, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { Debug.Assert(feed != null, "feed != null"); // Check for annotations on the feed that occur after the feed itself. (Note: the only allowed one is odata.nextLink, and we fail for anything else.) // We do this slightly differently depending on whether the feed was an expanded navigation or a top-level feed. if (expandedNavigationLinkInfo != null) { this.ReadExpandedFeedAnnotationsAtFeedEnd(feed, expandedNavigationLinkInfo); } else { Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null"); // Check for feed instance annotations that appear after the feed. bool isReordering = this.JsonReader is ReorderingJsonReader; this.ReadTopLevelFeedAnnotations(feed, duplicatePropertyNamesChecker, /*forFeedStart*/false, /*readAllFeedProperties*/isReordering); } }
/// <summary> /// Checks if there is a next link annotation immediately after an expanded feed, and reads and stores it if there is one. /// We fail here if we encounter any other property annotation for the expanded navigation (since these should come before the property itself). /// </summary> /// <param name="feed">The feed that was just read.</param> /// <param name="expandedNavigationLinkInfo">The information for the current expanded navigation link being read.</param> private void ReadExpandedFeedAnnotationsAtFeedEnd(ODataFeedBase feed, ODataJsonLightReaderNavigationLinkInfo expandedNavigationLinkInfo) { Debug.Assert(expandedNavigationLinkInfo != null, "expandedNavigationLinkInfo != null"); Debug.Assert(expandedNavigationLinkInfo.NavigationLink.IsCollection == true, "Only collection navigation properties can have feed content."); // Look at the next property in the owning entry, if it's a property annotation for the expanded navigation link info property, read it. string propertyName, annotationName; while (this.JsonReader.NodeType == JsonNodeType.Property && TryParsePropertyAnnotation(this.JsonReader.GetPropertyName(), out propertyName, out annotationName) && string.CompareOrdinal(propertyName, expandedNavigationLinkInfo.NavigationLink.Name) == 0) { if (!this.ReadingResponse) { throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_UnexpectedPropertyAnnotation(propertyName, annotationName)); } // Read over the property name. this.JsonReader.Read(); switch (annotationName) { case ODataAnnotationNames.ODataNextLink: if (feed.NextPageLink != null) { throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_DuplicateExpandedFeedAnnotation(ODataAnnotationNames.ODataNextLink, expandedNavigationLinkInfo.NavigationLink.Name)); } // Read the property value. feed.NextPageLink = this.ReadAndValidateAnnotationStringValueAsUri(ODataAnnotationNames.ODataNextLink); break; case ODataAnnotationNames.ODataCount: if (feed.Count != null) { throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_DuplicateExpandedFeedAnnotation(ODataAnnotationNames.ODataCount, expandedNavigationLinkInfo.NavigationLink.Name)); } // Read the property value. feed.Count = this.ReadAndValidateAnnotationAsLongForIeee754Compatible(ODataAnnotationNames.ODataCount); break; case ODataAnnotationNames.ODataDeltaLink: // Delta links are not supported on expanded feeds. default: throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_UnexpectedPropertyAnnotationAfterExpandedFeed(annotationName, expandedNavigationLinkInfo.NavigationLink.Name)); } } }
/// <summary> /// Creates a navigation link info for a collection of entity reference links. /// </summary> /// <param name="navigationLink">The navigation link to report.</param> /// <param name="navigationProperty">The navigation property for which the link will be reported.</param> /// <param name="entityReferenceLinks">The entity reference links for the navigation link to report.</param> /// <param name="isExpanded">true if the navigation link is expanded.</param> /// <returns>The navigation link info created.</returns> internal static ODataJsonLightReaderNavigationLinkInfo CreateCollectionEntityReferenceLinksInfo( ODataNavigationLink navigationLink, IEdmNavigationProperty navigationProperty, LinkedList<ODataEntityReferenceLink> entityReferenceLinks, bool isExpanded) { Debug.Assert(navigationLink != null, "navigationLink != null"); Debug.Assert(navigationLink.IsCollection == true, "Collection entity reference can only be reported for a collection navigation links."); Debug.Assert(navigationProperty != null, "navigationProperty != null"); Debug.Assert(entityReferenceLinks == null || entityReferenceLinks.Count > 0, "entityReferenceLinks == null || entityReferenceLinks.Count > 0"); ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo = new ODataJsonLightReaderNavigationLinkInfo(navigationLink, navigationProperty, isExpanded); navigationLinkInfo.entityReferenceLinks = entityReferenceLinks; return navigationLinkInfo; }
/// <summary> /// Creates a navigation link info for a projected navigation link that is missing from the payload. /// </summary> /// <param name="navigationProperty">The navigation property for which the link will be reported.</param> /// <returns>The navigation link info created.</returns> internal static ODataJsonLightReaderNavigationLinkInfo CreateProjectedNavigationLinkInfo(IEdmNavigationProperty navigationProperty) { Debug.Assert(navigationProperty != null, "navigationProperty != null"); ODataNavigationLink navigationLink = new ODataNavigationLink { Name = navigationProperty.Name, IsCollection = navigationProperty.Type.IsCollection() }; ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo = new ODataJsonLightReaderNavigationLinkInfo(navigationLink, navigationProperty, /*isExpanded*/ false); return navigationLinkInfo; }
/// <summary> /// Creates a navigation link info for a singleton entity reference link. /// </summary> /// <param name="navigationLink">The navigation link to report.</param> /// <param name="navigationProperty">The navigation property for which the link will be reported.</param> /// <param name="entityReferenceLink">The entity reference link for the navigation link to report.</param> /// <param name="isExpanded">true if the navigation link is expanded.</param> /// <returns>The navigation link info created.</returns> internal static ODataJsonLightReaderNavigationLinkInfo CreateSingletonEntityReferenceLinkInfo( ODataNavigationLink navigationLink, IEdmNavigationProperty navigationProperty, ODataEntityReferenceLink entityReferenceLink, bool isExpanded) { Debug.Assert(navigationLink != null, "navigationLink != null"); Debug.Assert(navigationLink.IsCollection == false, "Singleton entity reference can only be reported for a singleton navigation links."); Debug.Assert(navigationProperty != null, "navigationProperty != null"); ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo = new ODataJsonLightReaderNavigationLinkInfo(navigationLink, navigationProperty, isExpanded); if (entityReferenceLink != null) { navigationLinkInfo.entityReferenceLinks = new LinkedList<ODataEntityReferenceLink>(); navigationLinkInfo.entityReferenceLinks.AddFirst(entityReferenceLink); } return navigationLinkInfo; }
/// <summary> /// Creates a navigation link info for an expanded feed link. /// </summary> /// <param name="navigationLink">The navigation link to report.</param> /// <param name="navigationProperty">The navigation property for which the link will be reported.</param> /// <param name="expandedFeed">The expanded feed for the navigation link to report.</param> /// <returns>The navigation link info created.</returns> internal static ODataJsonLightReaderNavigationLinkInfo CreateExpandedFeedLinkInfo( ODataNavigationLink navigationLink, IEdmNavigationProperty navigationProperty, ODataFeed expandedFeed) { Debug.Assert(navigationLink != null, "navigationLink != null"); Debug.Assert(navigationLink.IsCollection == true, "Expanded feeds can only be reported for collection navigation links."); Debug.Assert(expandedFeed != null, "expandedFeed != null"); ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo = new ODataJsonLightReaderNavigationLinkInfo(navigationLink, navigationProperty, /*isExpanded*/ true); navigationLinkInfo.expandedFeed = expandedFeed; return navigationLinkInfo; }
/// <summary> /// Creates a navigation link info for an expanded entry link. /// </summary> /// <param name="navigationLink">The navigation link to report.</param> /// <param name="navigationProperty">The navigation property for which the link will be reported.</param> /// <returns>The navigation link info created.</returns> internal static ODataJsonLightReaderNavigationLinkInfo CreateExpandedEntryLinkInfo( ODataNavigationLink navigationLink, IEdmNavigationProperty navigationProperty) { Debug.Assert(navigationLink != null, "navigationLink != null"); Debug.Assert(navigationLink.IsCollection == false, "Expanded entry can only be reported for a singleton navigation link."); ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo = new ODataJsonLightReaderNavigationLinkInfo(navigationLink, navigationProperty, /*isExpanded*/ true); return navigationLinkInfo; }
/// <summary> /// Constructor creating a new reader scope. /// </summary> /// <param name="navigationLinkInfo">The navigation link info attached to this scope.</param> /// <param name="navigationSource">The navigation source we are going to read entities for.</param> /// <param name="expectedEntityType">The expected type for the scope.</param> /// <param name="odataUri">The odataUri parsed based on the context uri for current scope</param> /// <remarks>The <paramref name="expectedEntityType"/> has the following meaning /// it's the expected base type the entries in the expanded link (either the single entry /// or entries in the expanded feed). /// In all cases the specified type must be an entity type.</remarks> internal JsonLightNavigationLinkScope(ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo, IEdmNavigationSource navigationSource, IEdmEntityType expectedEntityType, ODataUri odataUri) : base(ODataReaderState.NavigationLinkStart, navigationLinkInfo.NavigationLink, navigationSource, expectedEntityType, odataUri) { this.NavigationLinkInfo = navigationLinkInfo; }
/// <summary> /// Starts the navigation link. /// Does metadata validation of the navigation link and sets up the reader to report it. /// </summary> /// <param name="navigationLinkInfo">The navigation link info for the navigation link to start.</param> private void StartNavigationLink(ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo) { Debug.Assert(navigationLinkInfo != null, "navigationLinkInfo != null"); ODataNavigationLink navigationLink = navigationLinkInfo.NavigationLink; IEdmNavigationProperty navigationProperty = navigationLinkInfo.NavigationProperty; Debug.Assert( this.jsonLightEntryAndFeedDeserializer.JsonReader.NodeType == JsonNodeType.Property || this.jsonLightEntryAndFeedDeserializer.JsonReader.NodeType == JsonNodeType.EndObject || this.jsonLightEntryAndFeedDeserializer.JsonReader.NodeType == JsonNodeType.StartObject || this.jsonLightEntryAndFeedDeserializer.JsonReader.NodeType == JsonNodeType.StartArray || this.jsonLightEntryAndFeedDeserializer.JsonReader.NodeType == JsonNodeType.PrimitiveValue && this.jsonLightEntryAndFeedDeserializer.JsonReader.Value == null, "Post-Condition: expected JsonNodeType.StartObject or JsonNodeType.StartArray or JsonNodeType.Primitive (null), or JsonNodeType.Property, JsonNodeType.EndObject"); Debug.Assert( navigationProperty != null || this.jsonLightInputContext.MessageReaderSettings.ReportUndeclaredLinkProperties, "A navigation property must be found for each link we find unless we're allowed to report undeclared links."); Debug.Assert(navigationLink != null, "navigationLink != null"); Debug.Assert(!string.IsNullOrEmpty(navigationLink.Name), "Navigation links must have a name."); Debug.Assert( navigationProperty == null || navigationLink.Name == navigationProperty.Name, "The navigation property must match the navigation link."); // we are at the beginning of a link IEdmEntityType targetEntityType = null; if (navigationProperty != null) { IEdmTypeReference navigationPropertyType = navigationProperty.Type; targetEntityType = navigationPropertyType.IsCollection() ? navigationPropertyType.AsCollection().ElementType().AsEntity().EntityDefinition() : navigationPropertyType.AsEntity().EntityDefinition(); } if (this.jsonLightInputContext.ReadingResponse) { // Hookup the metadata builder to the navigation link. // Note that we set the metadata builder even when navigationProperty is null, which is the case when the link is undeclared. // For undeclared links, we will apply conventional metadata evaluation just as declared links. ODataEntityMetadataBuilder entityMetadataBuilder = this.jsonLightEntryAndFeedDeserializer.MetadataContext.GetEntityMetadataBuilderForReader(this.CurrentEntryState, this.jsonLightInputContext.MessageReaderSettings.UseKeyAsSegment); navigationLink.MetadataBuilder = entityMetadataBuilder; } Debug.Assert(this.CurrentNavigationSource != null || this.readingParameter, "Json requires an navigation source when not reading parameter."); IEdmNavigationSource navigationSource = this.CurrentNavigationSource == null || navigationProperty == null ? null : this.CurrentNavigationSource.FindNavigationTarget(navigationProperty); ODataUri odataUri = null; if (navigationLinkInfo.NavigationLink.ContextUrl != null) { ODataPath odataPath = ODataJsonLightContextUriParser.Parse( this.jsonLightEntryAndFeedDeserializer.Model, UriUtils.UriToString(navigationLinkInfo.NavigationLink.ContextUrl), navigationLinkInfo.NavigationLink.IsCollection.GetValueOrDefault() ? ODataPayloadKind.Feed : ODataPayloadKind.Entry, this.jsonLightEntryAndFeedDeserializer.MessageReaderSettings.ReaderBehavior, this.jsonLightEntryAndFeedDeserializer.JsonLightInputContext.ReadingResponse).Path; odataUri = new ODataUri() { Path = odataPath }; } this.EnterScope(new JsonLightNavigationLinkScope(navigationLinkInfo, navigationSource, targetEntityType, odataUri)); }