/// <summary> /// Creates the value for the navigation property's link relation attribute. /// </summary> /// <param name="navigationLink">The link representing the navigation property for which the relation value is created.</param> /// <returns>The relation attribute value for the navigation property's link relation.</returns> internal static string ComputeODataNavigationLinkRelation(ODataNavigationLink navigationLink) { Debug.Assert(navigationLink != null, "navigationLink != null"); Debug.Assert(navigationLink.Name != null, "navigationLink.Name != null"); return string.Join("", new string[] { AtomConstants.ODataNavigationPropertiesRelatedLinkRelationPrefix, navigationLink.Name }); }
public ODataNavigationLinkTests() { this.navigationLink = new ODataNavigationLink(); var entry = new ODataEntry { TypeName = "ns.DerivedType", Properties = new[] { new ODataProperty{Name = "Id", Value = 1, SerializationInfo = new ODataPropertySerializationInfo{PropertyKind = ODataPropertyKind.Key}}, new ODataProperty{Name = "Name", Value = "Bob", SerializationInfo = new ODataPropertySerializationInfo{PropertyKind = ODataPropertyKind.ETag}} } }; var serializationInfo = new ODataFeedAndEntrySerializationInfo { NavigationSourceName = "Set", NavigationSourceEntityTypeName = "ns.BaseType", ExpectedTypeName = "ns.BaseType" }; var typeContext = ODataFeedAndEntryTypeContext.Create(serializationInfo, null, null, null, EdmCoreModel.Instance, true); var metadataContext = new TestMetadataContext(); var entryMetadataContext = ODataEntryMetadataContext.Create(entry, typeContext, serializationInfo, null, metadataContext, SelectedPropertiesNode.EntireSubtree); var metadataBuilder = new ODataConventionalEntityMetadataBuilder(entryMetadataContext, metadataContext, new ODataConventionalUriBuilder(ServiceUri, UrlConvention.CreateWithExplicitValue(false))); this.navigationLinkWithFullBuilder = new ODataNavigationLink { Name = "NavProp" }; this.navigationLinkWithFullBuilder.MetadataBuilder = metadataBuilder; this.navigationLinkWithNoOpBuilder = new ODataNavigationLink { Name = "NavProp" }; this.navigationLinkWithNoOpBuilder.MetadataBuilder = new NoOpEntityMetadataBuilder(entry); this.navigationLinkWithNullBuilder = new ODataNavigationLink { Name = "NavProp" }; this.navigationLinkWithNullBuilder.MetadataBuilder = ODataEntityMetadataBuilder.Null; }
/// <summary> /// Constructor. /// </summary> /// <param name="navigationLink">The navigation link.</param> /// <param name="navigationProperty">The navigation property for the link, if it's available.</param> internal ODataAtomReaderNavigationLinkDescriptor(ODataNavigationLink navigationLink, IEdmNavigationProperty navigationProperty) { Debug.Assert(navigationLink != null, "navigationLink != null"); this.navigationLink = navigationLink; this.navigationProperty = navigationProperty; }
/// <summary> /// Constructor. /// </summary> /// <param name="navigationLink">The navigation link.</param> /// <param name="navigationProperty">The navigation property for the link, if it's available.</param> internal ODataAtomReaderNavigationLinkDescriptor(ODataNavigationLink navigationLink, IEdmNavigationProperty navigationProperty) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(navigationLink != null, "navigationLink != null"); this.navigationLink = navigationLink; this.navigationProperty = navigationProperty; }
/// <summary> /// Creates the value for the navigation property's type attribute. /// </summary> /// <param name="navigationLink">The link representing the navigation property for which the type value is created.</param> /// <returns>The type attribute value for the navigation property.</returns> internal static string ComputeODataNavigationLinkType(ODataNavigationLink navigationLink) { Debug.Assert(navigationLink != null, "navigationLink != null"); Debug.Assert(navigationLink.IsCollection.HasValue, "navigationLink.IsCollection.HasValue"); // "application/atom+xml;type=entry" or type="application/atom+xml;type=feed" return navigationLink.IsCollection.Value ? MimeConstants.MimeApplicationAtomXmlTypeFeed : MimeConstants.MimeApplicationAtomXmlTypeEntry; }
/// <summary> /// Creates the value for the navigation property's link relation attribute. /// </summary> /// <param name="navigationLink">The link representing the navigation property for which the relation value is created.</param> /// <returns>The relation attribute value for the navigation property's link relation.</returns> internal static string ComputeODataNavigationLinkRelation(ODataNavigationLink navigationLink) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(navigationLink != null, "navigationLink != null"); Debug.Assert(navigationLink.Name != null, "navigationLink.Name != null"); return string.Join("/", new string[] { AtomConstants.ODataNamespace, AtomConstants.ODataNavigationPropertiesRelatedSegmentName, navigationLink.Name }); }
/// <summary> /// Constructor. /// </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="isExpanded">true if the navigation link is expanded.</param> private ODataJsonLightReaderNavigationLinkInfo(ODataNavigationLink navigationLink, IEdmNavigationProperty navigationProperty, bool isExpanded) { Debug.Assert(navigationLink != null, "navigationLink != null"); Debug.Assert(navigationProperty == null || navigationProperty.Name == navigationLink.Name, "The name of the navigation link doesn't match the name of the property."); this.navigationLink = navigationLink; this.navigationProperty = navigationProperty; this.isExpanded = isExpanded; }
private void AddBoundNavigationPropertyAnnotation(ODataItem item, ODataNavigationLink navigationLink, object boundValue) { var annotation = item.GetAnnotation <BoundNavigationPropertyAnnotation>(); if (annotation == null) { annotation = new BoundNavigationPropertyAnnotation { BoundProperties = new List <Tuple <ODataNavigationLink, object> >() }; item.SetAnnotation(annotation); } annotation.BoundProperties.Add(new Tuple <ODataNavigationLink, object>(navigationLink, boundValue)); }
public static AtomLinkMetadata Atom(this ODataNavigationLink navigationLink) { ExceptionUtils.CheckArgumentNotNull(navigationLink, "navigationLink"); AtomLinkMetadata linkMetadata = navigationLink.GetAnnotation <AtomLinkMetadata>(); if (linkMetadata == null) { linkMetadata = new AtomLinkMetadata(); navigationLink.SetAnnotation(linkMetadata); } return(linkMetadata); }
/// <summary> /// Start writing a navigation link with content. /// </summary> /// <param name="navigationLink">The navigation link to write.</param> protected override void StartNavigationLinkWithContent(ODataNavigationLink navigationLink) { Debug.Assert(navigationLink != null, "navigationLink != null"); Debug.Assert(!string.IsNullOrEmpty(navigationLink.Name), "The navigation link name should have been verified by now."); if (this.jsonLightOutputContext.WritingResponse) { // Write the navigation link metadata first. The rest is written by the content entry or feed. this.jsonLightEntryAndFeedSerializer.WriteNavigationLinkMetadata(navigationLink, this.DuplicatePropertyNamesChecker); } else { WriterValidationUtils.ValidateNavigationLinkHasCardinality(navigationLink); } }
/// <summary> /// Start writing a navigation link. /// </summary> /// <param name="navigationLink">Navigation link to write.</param> public override void WriteStart(ODataNavigationLink navigationLink) { if (this.testConfiguration.Synchronous) { this.writer.WriteStart(navigationLink); } else { #if WINDOWS_PHONE throw new TaupoNotSupportedException("This test is not supported in asynchronous mode in Silverlight or Windows Phone"); #else this.writer.WriteStartAsync(navigationLink).Wait(); #endif } }
protected override void VisitNavigationLink(ODataNavigationLink navigationLink) { bool?expectedIsCollectionValue; if (this.expectedIsCollectionValues != null && this.expectedIsCollectionValues.TryGetValue(navigationLink.Name, out expectedIsCollectionValue)) { this.assertionHandler.AreEqual( expectedIsCollectionValue, navigationLink.IsCollection, "Value for IsCollection on NavigationLink '{0}' is unexpected", navigationLink.Name); } base.VisitNavigationLink(navigationLink); }
protected override void WriteDeferredNavigationLink(ODataNavigationLink navigationLink) { if (navigationLink.Url == null) { throw new ODataException(Strings.ODataWriter_NavigationLinkMustSpecifyUrl); } this.jsonOutputContext.JsonWriter.WriteName(navigationLink.Name); this.jsonOutputContext.JsonWriter.StartObjectScope(); this.jsonOutputContext.JsonWriter.WriteName("__deferred"); this.jsonOutputContext.JsonWriter.StartObjectScope(); this.jsonOutputContext.JsonWriter.WriteName("uri"); this.jsonOutputContext.JsonWriter.WriteValue(this.jsonEntryAndFeedSerializer.UriToAbsoluteUriString(navigationLink.Url)); this.jsonOutputContext.JsonWriter.EndObjectScope(); this.jsonOutputContext.JsonWriter.EndObjectScope(); }
protected override void StartNavigationLinkWithContent(ODataNavigationLink navigationLink) { this.jsonOutputContext.JsonWriter.WriteName(navigationLink.Name); if (!this.jsonOutputContext.WritingResponse) { if (!navigationLink.IsCollection.HasValue) { throw new ODataException(Strings.ODataWriterCore_LinkMustSpecifyIsCollection); } if (navigationLink.IsCollection.Value) { this.jsonOutputContext.JsonWriter.StartArrayScope(); } } }
private IEnumerable <ODataNavigationLink> CreateNavigationLinks( IEnumerable <IEdmNavigationProperty> navigationProperties, EntityInstanceContext entityInstanceContext) { Contract.Assert(navigationProperties != null); Contract.Assert(entityInstanceContext != null); foreach (IEdmNavigationProperty navProperty in navigationProperties) { ODataNavigationLink navigationLink = CreateNavigationLink(navProperty, entityInstanceContext); if (navigationLink != null) { yield return(navigationLink); } } }
/// <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) { DebugUtils.CheckNoExternalCallers(); 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> /// Initializes an ODataNavigationLink instance for the deferred link payload. /// </summary> /// <param name="payloadElement">The deferred link to process.</param> public override void Visit(DeferredLink payloadElement) { Debug.Assert(this.currentLink != null); ODataNavigationLink navigationLink = this.currentLink; this.currentLink = null; // TODO, ckerer: where do I get the info whether this links is a singleton or collection? navigationLink.Url = new Uri(payloadElement.UriString); AddLinkMetadata(payloadElement, navigationLink); this.writer.WriteStart(navigationLink); base.Visit(payloadElement); this.writer.WriteEnd(); }
/// <summary> /// Gets the expanded content of a navigation link. /// </summary> /// <param name="navigationLink">The <see cref="ODataNavigationLink"/> to get the navigation content for.</param> /// <param name="expandedContent">The expanded content (if the method returns null), which can be either /// null (null expanded entry), or <see cref="ODataEntry"/> or <see cref="ODataFeed"/>.</param> /// <returns>true if the <paramref name="navigationLink"/> is expanded, or false otherwise.</returns> public static bool TryGetExpandedContent(this ODataNavigationLink navigationLink, out object expandedContent) { ExceptionUtilities.CheckArgumentNotNull(navigationLink, "navigationLink"); var expandedItemAnnotation = navigationLink.GetAnnotation <ODataNavigationLinkExpandedItemObjectModelAnnotation>(); if (expandedItemAnnotation != null) { expandedContent = expandedItemAnnotation.ExpandedItem; return(true); } else { expandedContent = null; return(false); } }
public void PropertyGettersAndSettersTest() { string name = "ODataNavigationLink"; Uri url = new Uri("http://odatatest.org/"); bool isCollection = true; ODataNavigationLink navigationLink = new ODataNavigationLink() { Name = name, Url = url, IsCollection = isCollection, }; this.Assert.AreEqual(name, navigationLink.Name, "Expected equal name values."); this.Assert.AreSame(url, navigationLink.Url, "Expected reference equal values for property 'Url'."); this.Assert.AreEqual(isCollection, navigationLink.IsCollection, "Expected equal values for property 'IsCollection'"); }
/// <summary> /// Finish writing a navigation link with content. /// </summary> /// <param name="navigationLink">The navigation link to write.</param> protected override void EndNavigationLinkWithContent(ODataNavigationLink navigationLink) { Debug.Assert(navigationLink != null, "navigationLink != null"); if (this.verboseJsonOutputContext.WritingResponse) { // Nothing to do here, the navigation link is represented as a JSON object which is either the feed or entry } else { // In request, if the navigation link is a collection we must close the array we've started. if (navigationLink.IsCollection.Value) { this.verboseJsonOutputContext.JsonWriter.EndArrayScope(); } } }
public void NavigationLinkValidationTest() { var testCases = new[] { new NavigationLinkValidationTestCase { // null link name is not valid InvalidateLink = link => link.Name = null, ExpectedException = link => ODataExpectedExceptions.ODataException("ValidationUtils_LinkMustSpecifyName"), }, new NavigationLinkValidationTestCase { // empty link name is not valid InvalidateLink = link => link.Name = string.Empty, ExpectedException = link => ODataExpectedExceptions.ODataException("ValidationUtils_LinkMustSpecifyName"), }, new NavigationLinkValidationTestCase { // null link Url is not valid InvalidateLink = link => link.Url = null, ExpectedException = link => ODataExpectedExceptions.ODataException("WriterValidationUtils_NavigationLinkMustSpecifyUrl", link.Name), SkipTestConfiguration = (testConfiguration) => testConfiguration.Format == ODataFormat.Json || testConfiguration.IsRequest }, }; var testDescriptors = testCases.Select(testCase => { ODataNavigationLink link = ObjectModelUtils.CreateDefaultCollectionLink(); testCase.InvalidateLink(link); return(new PayloadWriterTestDescriptor <ODataItem>( this.Settings, link, testConfiguration => new WriterTestExpectedResults(this.Settings.ExpectedResultSettings) { ExpectedException2 = testCase.ExpectedException(link) }) { SkipTestConfiguration = testCase.SkipTestConfiguration }); }); // TODO: Fix places where we've lost JsonVerbose coverage to add JsonLight this.CombinatorialEngineProvider.RunCombinations( testDescriptors.PayloadCases(WriterPayloads.NavigationLinkOnlyPayloads), this.WriterTestConfigurationProvider.ExplicitFormatConfigurations.Where(tc => tc.Format == ODataFormat.Atom), (testDescriptor, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor.DeferredLinksToEntityReferenceLinksInRequest(testConfiguration), testConfiguration, this.Assert, this.Logger); }); }
protected override bool ReadAtNavigationLinkEndImplementation() { IEdmNavigationProperty property; base.PopScope(ODataReaderState.NavigationLinkEnd); ODataNavigationLink navigationLink = this.jsonEntryAndFeedDeserializer.ReadEntryContent(this.CurrentEntryState, out property); if (navigationLink == null) { this.ReplaceScope(ODataReaderState.EntryEnd); } else { this.StartNavigationLink(navigationLink, property); } return(true); }
public void PropertySettersNullTest() { ODataNavigationLink navigationLink = new ODataNavigationLink() { Name = "NewLink", Url = new Uri("http://odata.org"), IsCollection = true, }; navigationLink.Name = null; navigationLink.Url = null; navigationLink.IsCollection = null; this.Assert.IsNull(navigationLink.Name, "Expected null value for property 'Name'."); this.Assert.IsNull(navigationLink.Url, "Expected null value for property 'Url'."); this.Assert.IsNull(navigationLink.Url, "Expected null value for property 'IsCollection'."); }
public void InitTest() { this.navigationLink = new ODataNavigationLink(); var entry = new ODataEntry { TypeName = "ns.DerivedType", Properties = new[] { new ODataProperty { Name = "Id", Value = 1, SerializationInfo = new ODataPropertySerializationInfo { PropertyKind = ODataPropertyKind.Key } }, new ODataProperty { Name = "Name", Value = "Bob", SerializationInfo = new ODataPropertySerializationInfo { PropertyKind = ODataPropertyKind.ETag } } } }; var serializationInfo = new ODataFeedAndEntrySerializationInfo { NavigationSourceName = "Set", NavigationSourceEntityTypeName = "ns.BaseType", ExpectedTypeName = "ns.BaseType" }; var typeContext = ODataFeedAndEntryTypeContext.Create(serializationInfo, null, null, null, EdmCoreModel.Instance, true); var metadataContext = new TestMetadataContext(); var entryMetadataContext = ODataEntryMetadataContext.Create(entry, typeContext, serializationInfo, null, metadataContext, SelectedPropertiesNode.EntireSubtree); var metadataBuilder = new ODataConventionalEntityMetadataBuilder(entryMetadataContext, metadataContext, new ODataConventionalUriBuilder(ServiceUri, UrlConvention.CreateWithExplicitValue(false))); this.navigationLinkWithFullBuilder = new ODataNavigationLink { Name = "NavProp" }; this.navigationLinkWithFullBuilder.MetadataBuilder = metadataBuilder; this.navigationLinkWithNoOpBuilder = new ODataNavigationLink { Name = "NavProp" }; this.navigationLinkWithNoOpBuilder.MetadataBuilder = new NoOpEntityMetadataBuilder(entry); this.navigationLinkWithNullBuilder = new ODataNavigationLink { Name = "NavProp" }; this.navigationLinkWithNullBuilder.MetadataBuilder = ODataEntityMetadataBuilder.Null; }
public void OnNavLinkEndShouldBeFired() { Person p = new Person(); Address a = new Address(); ODataNavigationLink link = new ODataNavigationLink(); var wrappedWriter = this.SetupTestActionExecuted((context, requestPipeline) => { requestPipeline.OnNavigationLinkEnding((args) => { args.Source.Should().BeSameAs(p); args.Target.Should().BeSameAs(a); args.Link.Name = "foo"; }); }); wrappedWriter.WriteEnd(link, p, a); link.Name.Should().Be("foo"); }
private void WriteEntry(ODataWriter writer, ODataEntry entry) { writer.WriteStart(entry); var annotation = entry.GetAnnotation <ODataEntryNavigationLinksObjectModelAnnotation>(); ODataNavigationLink navLink = null; if (annotation != null) { for (int i = 0; i < annotation.Count; ++i) { bool found = annotation.TryGetNavigationLinkAt(i, out navLink); ExceptionUtilities.Assert(found, "Navigation links should be ordered sequentially for writing"); this.WriteNavigationLink(writer, navLink); } } writer.WriteEnd(); }
private async Task <IEnumerable <ODataNavigationLink> > CreateNavigationLinksAsync( IEnumerable <IEdmNavigationProperty> navigationProperties, EntityInstanceContext entityInstanceContext) { Contract.Assert(navigationProperties != null); Contract.Assert(entityInstanceContext != null); List <ODataNavigationLink> result = new List <ODataNavigationLink>(); foreach (IEdmNavigationProperty navProperty in navigationProperties) { ODataNavigationLink navigationLink = await CreateNavigationLinkAsync(navProperty, entityInstanceContext); if (navigationLink != null) { result.Add(navigationLink); } } return(result); }
/// <summary> /// Writes the navigation link end m:inline and end atom:link elements if there's a parent navigation link. /// </summary> private void CheckAndWriteParentNavigationLinkEndForInlineElement() { Debug.Assert(this.State == WriterState.Entry || this.State == WriterState.Feed, "Only entry or feed can be written into a link with inline."); ODataNavigationLink parentNavigationLink = this.ParentNavigationLink; if (parentNavigationLink != null) { // We postponed writing the surrounding atom:link and m:inline until now since in request a single navigation link can have // multiple items in its content, each of which is written as a standalone atom:link. Thus the EndNavigationLinkWithContent is only called // once, but we may need to write multiple atom:link elements. // </m:inline> this.atomOutputContext.XmlWriter.WriteEndElement(); // </atom:link> this.WriteNavigationLinkEnd(); } }
private static MaterializerNavigationLink GetPropertyOrThrow(IEnumerable <ODataNavigationLink> links, string propertyName, string entryIdentity) { Func <ODataNavigationLink, bool> predicate = null; ODataNavigationLink link = null; if (links != null) { if (predicate == null) { predicate = p => p.Name == propertyName; } link = links.Where <ODataNavigationLink>(predicate).FirstOrDefault <ODataNavigationLink>(); } if (link == null) { throw new InvalidOperationException(System.Data.Services.Client.Strings.AtomMaterializer_PropertyMissing(propertyName, entryIdentity)); } return(MaterializerNavigationLink.GetLink(link)); }
/// <summary> /// Adds a navigation link. /// </summary> /// <param name="link">The link.</param> public void AddNavigationLink(ODataNavigationLink link) { if (this.IsAtomOrTracking) { this.EntityDescriptor.AddNavigationLink(link.Name, link.Url); Uri associationLinkUrl = link.AssociationLinkUrl; if (associationLinkUrl != null) { this.EntityDescriptor.AddAssociationLink(link.Name, associationLinkUrl); } } if (this.navigationLinks == ODataMaterializer.EmptyLinks) { this.navigationLinks = new List <ODataNavigationLink>(); } this.navigationLinks.Add(link); }
/// <summary> /// Writes the navigation link's start element and atom metadata. /// </summary> /// <param name="navigationLink">The navigation link to write.</param> /// <param name="navigationLinkUrlOverride">Url to use for the navigation link. If this is specified the Url property on the <paramref name="navigationLink"/> /// will be ignored. If this parameter is null, the Url from the navigation link is used.</param> private void WriteNavigationLinkStart(ODataNavigationLink navigationLink, Uri navigationLinkUrlOverride) { // IsCollection is required for ATOM if (!navigationLink.IsCollection.HasValue) { throw new ODataException(o.Strings.ODataWriterCore_LinkMustSpecifyIsCollection); } // Navigation link must specify the Url // NOTE: we currently only require a non-null Url for ATOM payloads and non-expanded navigation links in JSON. // There is no place in JSON to write a Url if the navigation link is expanded. We can't change that for v1 and v2; we // might fix the protocol for v3. if (navigationLink.Url == null) { throw new ODataException(o.Strings.ODataWriter_NavigationLinkMustSpecifyUrl); } this.atomEntryAndFeedSerializer.WriteNavigationLinkStart(navigationLink, navigationLinkUrlOverride); }
/// <summary> /// Start writing an entry. /// </summary> /// <param name="entry">The entry to write.</param> protected override void StartEntry(ODataEntry entry) { ODataNavigationLink parentNavLink = this.ParentNavigationLink; if (parentNavLink != null) { // Write the property name of an expanded navigation property to start the value. this.jsonLightOutputContext.JsonWriter.WriteName(parentNavLink.Name); } if (entry == null) { Debug.Assert( parentNavLink != null && !parentNavLink.IsCollection.Value, "when entry == null, it has to be and expanded single entry navigation"); // this is a null expanded single entry and it is null, so write a JSON null as value. this.jsonLightOutputContext.JsonWriter.WriteValue(null); return; } // Write just the object start, nothing else, since we might not have complete information yet this.jsonLightOutputContext.JsonWriter.StartObjectScope(); JsonLightEntryScope entryScope = this.CurrentEntryScope; if (this.IsTopLevel) { // Write odata.metadata this.jsonLightEntryAndFeedSerializer.TryWriteEntryMetadataUri(entryScope.GetOrCreateTypeContext(this.jsonLightOutputContext.Model, this.jsonLightOutputContext.WritingResponse)); } // Write the annotation group in responses (if any) this.jsonLightEntryAndFeedSerializer.WriteAnnotationGroup(entry); // Write the metadata this.jsonLightEntryAndFeedSerializer.WriteEntryStartMetadataProperties(entryScope); this.jsonLightEntryAndFeedSerializer.WriteEntryMetadataProperties(entryScope); // Write custom instance annotations this.jsonLightEntryAndFeedSerializer.InstanceAnnotationWriter.WriteInstanceAnnotations(entry.InstanceAnnotations, entryScope.InstanceAnnotationWriteTracker); }
/// <summary> /// Visits a navigation link item. /// </summary> /// <param name="navigationLink">The navigation link to visit.</param> protected virtual void VisitNavigationLink(ODataNavigationLink navigationLink) { object expandedContent; if (navigationLink.TryGetExpandedContent(out expandedContent) && expandedContent != null) { List <ODataItem> items = expandedContent as List <ODataItem>; if (items != null) { foreach (ODataItem item in items) { this.Visit(item); } } else { this.Visit(expandedContent); } } }
/// <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); }
private ODataNavigationLink ReadNavigationLink() { MaterializerEntry entry; ODataFeed feed; ODataNavigationLink item = (ODataNavigationLink)this.reader.Item; if (this.TryReadFeedOrEntry(false, out feed, out entry)) { if (feed != null) { MaterializerNavigationLink.CreateLink(item, feed); } else { MaterializerNavigationLink.CreateLink(item, entry); } this.ReadAndExpectState(ODataReaderState.NavigationLinkEnd); } this.ExpectState(ODataReaderState.NavigationLinkEnd); return(item); }
/// <summary> /// Writes the navigation link's start element and atom metadata. /// </summary> /// <param name="navigationLink">The navigation link to write.</param> /// <param name="navigationLinkUrlOverride">Url to use for the navigation link. If this is specified the Url property on the <paramref name="navigationLink"/> /// will be ignored. If this parameter is null, the Url from the navigation link is used.</param> internal void WriteNavigationLinkStart(ODataNavigationLink navigationLink, Uri navigationLinkUrlOverride) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(navigationLink != null, "navigationLink != null"); Debug.Assert(!string.IsNullOrEmpty(navigationLink.Name), "The navigation link name was not verified yet."); Debug.Assert(navigationLink.Url != null, "The navigation link Url was not verified yet."); Debug.Assert(navigationLink.IsCollection.HasValue, "navigationLink.IsCollection.HasValue"); // <atom:link> this.XmlWriter.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomLinkElementName, AtomConstants.AtomNamespace); string linkRelation = AtomUtils.ComputeODataNavigationLinkRelation(navigationLink); string linkType = AtomUtils.ComputeODataNavigationLinkType(navigationLink); string linkTitle = navigationLink.Name; Uri navigationLinkUrl = navigationLinkUrlOverride ?? navigationLink.Url; AtomLinkMetadata linkMetadata = navigationLink.GetAnnotation <AtomLinkMetadata>(); AtomLinkMetadata mergedMetadata = ODataAtomWriterMetadataUtils.MergeLinkMetadata(linkMetadata, linkRelation, navigationLinkUrl, linkTitle, linkType); this.atomEntryMetadataSerializer.WriteAtomLinkAttributes(mergedMetadata, null /* etag */); }
/// <summary> /// Start writing a deferred (non-expanded) navigation link. /// </summary> /// <param name="navigationLink">The navigation link to write.</param> protected override void WriteDeferredNavigationLink(ODataNavigationLink navigationLink) { Debug.Assert(navigationLink != null, "navigationLink != null"); Debug.Assert(this.jsonLightOutputContext.WritingResponse, "Deferred links are only supported in response, we should have verified this already."); // A deferred navigation link is just the link metadata, no value. this.jsonLightEntryAndFeedSerializer.WriteNavigationLinkMetadata(navigationLink, this.DuplicatePropertyNamesChecker); }
/// <summary> /// Reads a navigation link in entry element. /// </summary> /// <param name="entryState">The reader entry state for the entry being read.</param> /// <param name="linkRelation">The value of the rel attribute of the link to read, unescaped parsed URI.</param> /// <param name="linkHRef">The value of the href attribute of the link to read.</param> /// <returns>A descriptor of a navigation link if a navigation link was found; null otherwise.</returns> /// <remarks> /// Pre-Condition: XmlNodeType.Element atom:link - the start tag of the atom:link element to read. /// Post-Condition: XmlNodeType.Element atom:link - the start tag of the atom:link element - the reader doesn't move /// </remarks> private ODataAtomReaderNavigationLinkDescriptor TryReadNavigationLinkInEntry( IODataAtomReaderEntryState entryState, string linkRelation, string linkHRef) { Debug.Assert(linkRelation != null, "linkRelation != null"); this.XmlReader.AssertNotBuffering(); this.AssertXmlCondition(XmlNodeType.Element); Debug.Assert( this.XmlReader.NamespaceURI == AtomConstants.AtomNamespace && this.XmlReader.LocalName == AtomConstants.AtomLinkElementName, "The XML reader must be on the atom:link element for this method to work."); // We will ignore navigation links with empty property names string navigationLinkName = AtomUtils.GetNameFromAtomLinkRelationAttribute(linkRelation, AtomConstants.ODataNavigationPropertiesRelatedLinkRelationPrefix); if (string.IsNullOrEmpty(navigationLinkName)) { return null; } // Lookup the property in metadata // Note that we already verified that the navigation link name is not empty. IEdmNavigationProperty navigationProperty = ReaderValidationUtils.ValidateNavigationPropertyDefined(navigationLinkName, entryState.EntityType, this.MessageReaderSettings); // Navigation link ODataNavigationLink navigationLink = new ODataNavigationLink { Name = navigationLinkName }; // Get the type of the link string navigationLinkType = this.XmlReader.GetAttribute(this.AtomTypeAttributeName, this.EmptyNamespace); // [Astoria-ODataLib-Integration] Handling of type attribute value on atom:link element. // The behavior of ODataLib is: // Parse the type as content type // Compare media type names ignoring case (as per spec), compare parameter type names ignoring case // If it's application/atom+xml without type parameter or invalid type parameter - use it as a navigation link without specifying collection/singleton (pending metadata validation) // If it's application/atom+xml with type='feed' - use it as a navigation link assuming it's a collection (pending metadata validation) // If it's application/atom+xml with type='entry' - use it as a navigation link assuming it's a singleton (pending metadata validation) // In any other case - skip this link and treat it as if it's not a navigation link. // Note that parsing the type means we may fail if it's not a valid content type. // Missing and invalid type attributes are allowed. We will infer the cardinality either from the model or when expanding the link. if (!string.IsNullOrEmpty(navigationLinkType)) { // Fast path for most common link types bool hasEntryType, hasFeedType; bool isExactMatch = AtomUtils.IsExactNavigationLinkTypeMatch(navigationLinkType, out hasEntryType, out hasFeedType); if (!isExactMatch) { // If the fast path did not work, we have to fully parse the media type. string mediaTypeName, mediaTypeCharset; IList<KeyValuePair<string, string>> contentTypeParameters = HttpUtils.ReadMimeType(navigationLinkType, out mediaTypeName, out mediaTypeCharset); if (!HttpUtils.CompareMediaTypeNames(mediaTypeName, MimeConstants.MimeApplicationAtomXml)) { return null; } string typeParameterValue = null; if (contentTypeParameters != null) { for (int contentTypeParameterIndex = 0; contentTypeParameterIndex < contentTypeParameters.Count; contentTypeParameterIndex++) { KeyValuePair<string, string> contentTypeParameter = contentTypeParameters[contentTypeParameterIndex]; if (HttpUtils.CompareMediaTypeParameterNames(MimeConstants.MimeTypeParameterName, contentTypeParameter.Key)) { typeParameterValue = contentTypeParameter.Value; break; } } } if (typeParameterValue != null) { if (string.Compare(typeParameterValue, MimeConstants.MimeTypeParameterValueEntry, StringComparison.OrdinalIgnoreCase) == 0) { hasEntryType = true; } else if (string.Compare(typeParameterValue, MimeConstants.MimeTypeParameterValueFeed, StringComparison.OrdinalIgnoreCase) == 0) { hasFeedType = true; } } } if (hasEntryType) { navigationLink.IsCollection = false; } else if (hasFeedType) { navigationLink.IsCollection = true; } } // We allow missing HREF on a link and simply report null. if (linkHRef != null) { navigationLink.Url = this.ProcessUriFromPayload(linkHRef, this.XmlReader.XmlBaseUri); } this.XmlReader.MoveToElement(); // Read and store ATOM link metadata (captures extra info like lang, title) if ATOM metadata reading is turned on. AtomLinkMetadata atomLinkMetadata = this.EntryMetadataDeserializer.ReadAtomLinkElementInEntryContent(linkRelation, linkHRef); if (atomLinkMetadata != null) { navigationLink.SetAnnotation(atomLinkMetadata); } return new ODataAtomReaderNavigationLinkDescriptor(navigationLink, navigationProperty); }
/// <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> /// Constructor to create a new JSON Light navigation link scope. /// </summary> /// <param name="writerState">The writer state for the new scope.</param> /// <param name="navLink">The navigation link for the new scope.</param> /// <param name="navigationSource">The navigation source we are going to write entities for.</param> /// <param name="entityType">The entity type for the entries in the feed to be written (or null if the entity set base type should be used).</param> /// <param name="skipWriting">true if the content of the scope to create should not be written.</param> /// <param name="selectedProperties">The selected properties of this scope.</param> /// <param name="odataUri">The ODataUri info of this scope.</param> internal JsonLightNavigationLinkScope(WriterState writerState, ODataNavigationLink navLink, IEdmNavigationSource navigationSource, IEdmEntityType entityType, bool skipWriting, SelectedPropertiesNode selectedProperties, ODataUri odataUri) : base(writerState, navLink, navigationSource, entityType, skipWriting, selectedProperties, odataUri) { }
/// <summary> /// Creates a new JSON Light navigation link scope. /// </summary> /// <param name="writerState">The writer state for the new scope.</param> /// <param name="navLink">The navigation link for the new scope.</param> /// <param name="navigationSource">The navigation source we are going to write entities for.</param> /// <param name="entityType">The entity type for the entries in the feed to be written (or null if the entity set base type should be used).</param> /// <param name="skipWriting">true if the content of the scope to create should not be written.</param> /// <param name="selectedProperties">The selected properties of this scope.</param> /// <param name="odataUri">The ODataUri info of this scope.</param> /// <returns>The newly created JSON Light navigation link scope.</returns> protected override NavigationLinkScope CreateNavigationLinkScope(WriterState writerState, ODataNavigationLink navLink, IEdmNavigationSource navigationSource, IEdmEntityType entityType, bool skipWriting, SelectedPropertiesNode selectedProperties, ODataUri odataUri) { return new JsonLightNavigationLinkScope(writerState, navLink, navigationSource, entityType, skipWriting, selectedProperties, odataUri); }
/// <summary> /// Write an entity reference link. /// </summary> /// <param name="parentNavigationLink">The parent navigation link which is being written around the entity reference link.</param> /// <param name="entityReferenceLink">The entity reference link to write.</param> protected override void WriteEntityReferenceInNavigationLinkContent(ODataNavigationLink parentNavigationLink, ODataEntityReferenceLink entityReferenceLink) { Debug.Assert(parentNavigationLink != null, "parentNavigationLink != null"); Debug.Assert(entityReferenceLink != null, "entityReferenceLink != null"); Debug.Assert(!this.jsonLightOutputContext.WritingResponse, "Entity reference links are only supported in request, we should have verified this already."); // In JSON Light, we can only write entity reference links at the beginning of a navigation link in requests; // once we wrote a feed, entity reference links are not allowed anymore (we require all the entity reference // link to come first because of the grouping in the JSON Light wire format). JsonLightNavigationLinkScope navigationLinkScope = (JsonLightNavigationLinkScope)this.CurrentScope; if (navigationLinkScope.FeedWritten) { throw new ODataException(OData.Core.Strings.ODataJsonLightWriter_EntityReferenceLinkAfterFeedInRequest); } if (!navigationLinkScope.EntityReferenceLinkWritten) { // Write the property annotation for the entity reference link(s) this.odataAnnotationWriter.WritePropertyAnnotationName(parentNavigationLink.Name, ODataAnnotationNames.ODataBind); Debug.Assert(parentNavigationLink.IsCollection.HasValue, "parentNavigationLink.IsCollection.HasValue"); if (parentNavigationLink.IsCollection.Value) { this.jsonWriter.StartArrayScope(); } navigationLinkScope.EntityReferenceLinkWritten = true; } Debug.Assert(entityReferenceLink.Url != null, "The entity reference link Url should have been validated by now."); this.jsonWriter.WriteValue(this.jsonLightEntryAndFeedSerializer.UriToString(entityReferenceLink.Url)); }
/// <summary> /// Writes the navigation link's start element and atom metadata. /// </summary> /// <param name="navigationLink">The navigation link to write.</param> /// <param name="navigationLinkUrlOverride">Url to use for the navigation link. If this is specified the Url property on the <paramref name="navigationLink"/> /// will be ignored. If this parameter is null, the Url from the navigation link is used.</param> internal void WriteNavigationLinkStart(ODataNavigationLink navigationLink, Uri navigationLinkUrlOverride) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(navigationLink != null, "navigationLink != null"); Debug.Assert(!string.IsNullOrEmpty(navigationLink.Name), "The navigation link name was not verified yet."); Debug.Assert(navigationLink.Url != null, "The navigation link Url was not verified yet."); Debug.Assert(navigationLink.IsCollection.HasValue, "navigationLink.IsCollection.HasValue"); // <atom:link> this.XmlWriter.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomLinkElementName, AtomConstants.AtomNamespace); string linkRelation = AtomUtils.ComputeODataNavigationLinkRelation(navigationLink); string linkType = AtomUtils.ComputeODataNavigationLinkType(navigationLink); string linkTitle = navigationLink.Name; Uri navigationLinkUrl = navigationLinkUrlOverride ?? navigationLink.Url; AtomLinkMetadata linkMetadata = navigationLink.GetAnnotation<AtomLinkMetadata>(); AtomLinkMetadata mergedMetadata = ODataAtomWriterMetadataUtils.MergeLinkMetadata(linkMetadata, linkRelation, navigationLinkUrl, linkTitle, linkType); this.atomEntryMetadataSerializer.WriteAtomLinkAttributes(mergedMetadata, null /* etag */); }
/// <summary> /// Writes the navigation link's start element and atom metadata. /// </summary> /// <param name="navigationLink">The navigation link to write.</param> /// <param name="navigationLinkUrlOverride">Url to use for the navigation link. If this is specified the Url property on the <paramref name="navigationLink"/> /// will be ignored. If this parameter is null, the Url from the navigation link is used.</param> private void WriteNavigationLinkStart(ODataNavigationLink navigationLink, Uri navigationLinkUrlOverride) { WriterValidationUtils.ValidateNavigationLinkHasCardinality(navigationLink); WriterValidationUtils.ValidateNavigationLinkUrlPresent(navigationLink); this.atomEntryAndFeedSerializer.WriteNavigationLinkStart(navigationLink, navigationLinkUrlOverride); }
/// <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> /// Reads the information of a deferred link. /// </summary> /// <param name="entryState">The state of the reader for entry to read.</param> /// <param name="navigationPropertyName">The name of the navigation property for which to read the deferred link.</param> /// <param name="navigationProperty">The navigation property for which to read the deferred link. This can be null.</param> /// <returns>Returns the navigation link info for the deferred navigation link read.</returns> /// <remarks> /// This method doesn't move the reader. /// </remarks> private static ODataJsonLightReaderNavigationLinkInfo ReadDeferredNavigationLink(IODataJsonLightReaderEntryState entryState, string navigationPropertyName, IEdmNavigationProperty navigationProperty) { Debug.Assert(entryState != null, "entryState != null"); Debug.Assert(!string.IsNullOrEmpty(navigationPropertyName), "!string.IsNullOrEmpty(navigationPropertyName)"); Debug.Assert(navigationProperty == null || navigationPropertyName == navigationProperty.Name, "navigationProperty == null || navigationPropertyName == navigationProperty.Name"); ODataNavigationLink navigationLink = new ODataNavigationLink() { Name = navigationPropertyName, IsCollection = navigationProperty == null ? null : (bool?)navigationProperty.Type.IsCollection() }; Dictionary<string, object> propertyAnnotations = entryState.DuplicatePropertyNamesChecker.GetODataPropertyAnnotations(navigationLink.Name); if (propertyAnnotations != null) { foreach (KeyValuePair<string, object> propertyAnnotation in propertyAnnotations) { switch (propertyAnnotation.Key) { case ODataAnnotationNames.ODataNavigationLinkUrl: Debug.Assert(propertyAnnotation.Value is Uri && propertyAnnotation.Value != null, "The odata.navigationLinkUrl annotation should have been parsed as a non-null Uri."); navigationLink.Url = (Uri)propertyAnnotation.Value; break; case ODataAnnotationNames.ODataAssociationLinkUrl: Debug.Assert(propertyAnnotation.Value is Uri && propertyAnnotation.Value != null, "The odata.associationLinkUrl annotation should have been parsed as a non-null Uri."); navigationLink.AssociationLinkUrl = (Uri)propertyAnnotation.Value; break; default: throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_UnexpectedDeferredLinkPropertyAnnotation(navigationLink.Name, propertyAnnotation.Key)); } } } return ODataJsonLightReaderNavigationLinkInfo.CreateDeferredLinkInfo(navigationLink, navigationProperty); }
/// <summary> /// Start writing a navigation link with content. /// </summary> /// <param name="navigationLink">The navigation link to write.</param> protected override void StartNavigationLinkWithContent(ODataNavigationLink navigationLink) { Debug.Assert(navigationLink != null, "navigationLink != null"); Debug.Assert(!string.IsNullOrEmpty(navigationLink.Name), "The navigation link name should have been verified by now."); if (this.jsonLightOutputContext.WritingResponse) { // Write @odata.context annotation for navigation property var containedEntitySet = this.CurrentScope.NavigationSource as IEdmContainedEntitySet; if (containedEntitySet != null) { ODataContextUrlInfo info = ODataContextUrlInfo.Create( this.CurrentScope.NavigationSource, this.CurrentScope.EntityType.FullName(), containedEntitySet.NavigationProperty.Type.TypeKind() != EdmTypeKind.Collection, this.CurrentScope.ODataUri); this.jsonLightEntryAndFeedSerializer.WriteNavigationLinkContextUrl(navigationLink, info); } // Write the navigation link metadata first. The rest is written by the content entry or feed. this.jsonLightEntryAndFeedSerializer.WriteNavigationLinkMetadata(navigationLink, this.DuplicatePropertyNamesChecker); } else { WriterValidationUtils.ValidateNavigationLinkHasCardinality(navigationLink); } }
/// <summary> /// Finish writing a navigation link with content. /// </summary> /// <param name="navigationLink">The navigation link to write.</param> protected override void EndNavigationLinkWithContent(ODataNavigationLink navigationLink) { Debug.Assert(navigationLink != null, "navigationLink != null"); if (!this.jsonLightOutputContext.WritingResponse) { JsonLightNavigationLinkScope navigationLinkScope = (JsonLightNavigationLinkScope)this.CurrentScope; // If we wrote entity reference links for a collection navigation property but no // feed afterwards, we have to now close the array of links. if (navigationLinkScope.EntityReferenceLinkWritten && !navigationLinkScope.FeedWritten && navigationLink.IsCollection.Value) { this.jsonWriter.EndArrayScope(); } // In requests, the navigation link may have multiple entries in multiple feeds in it; if we // wrote at least one feed, close the resulting array here. if (navigationLinkScope.FeedWritten) { Debug.Assert(navigationLink.IsCollection.Value, "navigationLink.IsCollection.Value"); this.jsonWriter.EndArrayScope(); } } }
protected override void EndNavigationLinkWithContent(ODataNavigationLink navigationLink) { throw new NotImplementedException(); }
/// <summary> /// Reads expanded feed navigation link. /// </summary> /// <param name="entryState">The state of the reader for entry to read.</param> /// <param name="navigationProperty">The navigation property for which to read the expanded link.</param> /// <returns>The navigation link info for the expanded link read.</returns> /// <remarks> /// This method doesn't move the reader. /// </remarks> private static ODataJsonLightReaderNavigationLinkInfo ReadExpandedFeedNavigationLink(IODataJsonLightReaderEntryState entryState, IEdmNavigationProperty navigationProperty) { Debug.Assert(entryState != null, "entryState != null"); Debug.Assert(navigationProperty != null, "navigationProperty != null"); ODataNavigationLink navigationLink = new ODataNavigationLink() { Name = navigationProperty.Name, IsCollection = true }; ODataFeed expandedFeed = new ODataFeed(); Dictionary<string, object> propertyAnnotations = entryState.DuplicatePropertyNamesChecker.GetODataPropertyAnnotations(navigationLink.Name); if (propertyAnnotations != null) { foreach (KeyValuePair<string, object> propertyAnnotation in propertyAnnotations) { switch (propertyAnnotation.Key) { case ODataAnnotationNames.ODataNavigationLinkUrl: Debug.Assert(propertyAnnotation.Value is Uri && propertyAnnotation.Value != null, "The odata.navigationLinkUrl annotation should have been parsed as a non-null Uri."); navigationLink.Url = (Uri)propertyAnnotation.Value; break; case ODataAnnotationNames.ODataAssociationLinkUrl: Debug.Assert(propertyAnnotation.Value is Uri && propertyAnnotation.Value != null, "The odata.associationLinkUrl annotation should have been parsed as a non-null Uri."); navigationLink.AssociationLinkUrl = (Uri)propertyAnnotation.Value; break; case ODataAnnotationNames.ODataNextLink: Debug.Assert(propertyAnnotation.Value is Uri && propertyAnnotation.Value != null, "The odata.nextLink annotation should have been parsed as a non-null Uri."); expandedFeed.NextPageLink = (Uri)propertyAnnotation.Value; break; case ODataAnnotationNames.ODataCount: Debug.Assert(propertyAnnotation.Value is long && propertyAnnotation.Value != null, "The odata.count annotation should have been parsed as a non-null long."); expandedFeed.Count = (long?)propertyAnnotation.Value; break; case ODataAnnotationNames.ODataContext: Debug.Assert(propertyAnnotation.Value is Uri && propertyAnnotation.Value != null, "The odata.context annotation should have been parsed as a non-null Uri."); navigationLink.ContextUrl = (Uri)propertyAnnotation.Value; break; case ODataAnnotationNames.ODataDeltaLink: // Delta links are not supported on expanded feeds. default: throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_UnexpectedExpandedCollectionNavigationLinkPropertyAnnotation(navigationLink.Name, propertyAnnotation.Key)); } } } return ODataJsonLightReaderNavigationLinkInfo.CreateExpandedFeedLinkInfo(navigationLink, navigationProperty, expandedFeed); }
/// <summary> /// Reads expanded entry navigation link. /// </summary> /// <param name="entryState">The state of the reader for entry to read.</param> /// <param name="navigationProperty">The navigation property for which to read the expanded link.</param> /// <returns>The navigation link info for the expanded link read.</returns> /// <remarks> /// This method doesn't move the reader. /// </remarks> private static ODataJsonLightReaderNavigationLinkInfo ReadExpandedEntryNavigationLink(IODataJsonLightReaderEntryState entryState, IEdmNavigationProperty navigationProperty) { Debug.Assert(entryState != null, "entryState != null"); Debug.Assert(navigationProperty != null, "navigationProperty != null"); ODataNavigationLink navigationLink = new ODataNavigationLink() { Name = navigationProperty.Name, IsCollection = false }; Dictionary<string, object> propertyAnnotations = entryState.DuplicatePropertyNamesChecker.GetODataPropertyAnnotations(navigationLink.Name); if (propertyAnnotations != null) { foreach (KeyValuePair<string, object> propertyAnnotation in propertyAnnotations) { switch (propertyAnnotation.Key) { case ODataAnnotationNames.ODataNavigationLinkUrl: Debug.Assert(propertyAnnotation.Value is Uri && propertyAnnotation.Value != null, "The odata.navigationLinkUrl annotation should have been parsed as a non-null Uri."); navigationLink.Url = (Uri)propertyAnnotation.Value; break; case ODataAnnotationNames.ODataAssociationLinkUrl: Debug.Assert(propertyAnnotation.Value is Uri && propertyAnnotation.Value != null, "The odata.associationLinkUrl annotation should have been parsed as a non-null Uri."); navigationLink.AssociationLinkUrl = (Uri)propertyAnnotation.Value; break; case ODataAnnotationNames.ODataContext: Debug.Assert(propertyAnnotation.Value is Uri && propertyAnnotation.Value != null, "The odata.context annotation should have been parsed as a non-null Uri."); navigationLink.ContextUrl = (Uri)propertyAnnotation.Value; break; default: throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_UnexpectedExpandedSingletonNavigationLinkPropertyAnnotation(navigationLink.Name, propertyAnnotation.Key)); } } } return ODataJsonLightReaderNavigationLinkInfo.CreateExpandedEntryLinkInfo(navigationLink, navigationProperty); }
/// <summary> /// Start writing a navigation link. /// </summary> /// <param name="navigationLink">The navigation link to write.</param> protected override void WriteDeferredNavigationLink(ODataNavigationLink navigationLink) { Debug.Assert(navigationLink != null, "navigationLink != null"); Debug.Assert(this.atomOutputContext.WritingResponse, "Deferred links are only supported in response, we should have verified this already."); this.WriteNavigationLinkStart(navigationLink, null); this.WriteNavigationLinkEnd(); }
/// <summary> /// Reads entity reference links for a collection navigation link in request. /// </summary> /// <param name="entryState">The state of the reader for entry to read.</param> /// <param name="navigationProperty">The navigation property for which to read the entity reference links.</param> /// <param name="isExpanded">true if the navigation link is expanded.</param> /// <returns>The navigation link info for the entity reference links read.</returns> /// <remarks> /// This method doesn't move the reader. /// </remarks> private static ODataJsonLightReaderNavigationLinkInfo ReadEntityReferenceLinksForCollectionNavigationLinkInRequest( IODataJsonLightReaderEntryState entryState, IEdmNavigationProperty navigationProperty, bool isExpanded) { Debug.Assert(entryState != null, "entryState != null"); Debug.Assert(navigationProperty != null, "navigationProperty != null"); ODataNavigationLink navigationLink = new ODataNavigationLink() { Name = navigationProperty.Name, IsCollection = true }; Dictionary<string, object> propertyAnnotations = entryState.DuplicatePropertyNamesChecker.GetODataPropertyAnnotations(navigationLink.Name); LinkedList<ODataEntityReferenceLink> entityReferenceLinksList = null; if (propertyAnnotations != null) { foreach (KeyValuePair<string, object> propertyAnnotation in propertyAnnotations) { switch (propertyAnnotation.Key) { case ODataAnnotationNames.ODataBind: ODataEntityReferenceLink entityReferenceLink = propertyAnnotation.Value as ODataEntityReferenceLink; if (entityReferenceLink != null) { throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_StringValueForCollectionBindPropertyAnnotation(navigationLink.Name, ODataAnnotationNames.ODataBind)); } Debug.Assert( propertyAnnotation.Value is LinkedList<ODataEntityReferenceLink> && propertyAnnotation.Value != null, "The value of odata.bind property annotation must be either ODataEntityReferenceLink or List<ODataEntityReferenceLink>"); entityReferenceLinksList = (LinkedList<ODataEntityReferenceLink>)propertyAnnotation.Value; break; default: throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_UnexpectedNavigationLinkInRequestPropertyAnnotation( navigationLink.Name, propertyAnnotation.Key, ODataAnnotationNames.ODataBind)); } } } return ODataJsonLightReaderNavigationLinkInfo.CreateCollectionEntityReferenceLinksInfo(navigationLink, navigationProperty, entityReferenceLinksList, isExpanded); }
/// <summary> /// Start writing a navigation link with content. /// </summary> /// <param name="navigationLink">The navigation link to write.</param> protected override void StartNavigationLinkWithContent(ODataNavigationLink navigationLink) { Debug.Assert(navigationLink != null, "navigationLink != null"); // In requests, a navigation link can have multiple items in its content (in the OM view), either entity reference links or expanded entry/feed. // For each of these we need to write a separate atom:link element. So we can't write the start of the atom:link element here // instead we postpone writing it till the first item in the content. // In response, only one item can occur, but for simplicity we will keep the behavior the same as for request and thus postpone writing the atom:link // start element as well. // Note that the writer core guarantees that this method (and the matching EndNavigationLinkWithContent) is only called for navigation links // which actually have some content. The only case where navigation link doesn't have a content is in response, in which case this method won't // be called, instead the WriteDeferredNavigationLink is called. }
protected override void WriteDeferredNavigationLink(ODataNavigationLink navigationLink) { throw new NotImplementedException(); }
/// <summary> /// Finish writing a navigation link with content. /// </summary> /// <param name="navigationLink">The navigation link to write.</param> protected override void EndNavigationLinkWithContent(ODataNavigationLink navigationLink) { Debug.Assert(navigationLink != null, "navigationLink != null"); // We do not write the end element for atom:link here, since we need to write it for each item in the content separately. // See the detailed description in the StartNavigationLinkWithContent for details. }
protected override void WriteEntityReferenceInNavigationLinkContent(ODataNavigationLink parentNavigationLink, ODataEntityReferenceLink entityReferenceLink) { throw new NotImplementedException(); }
/// <summary> /// Write an entity reference link. /// </summary> /// <param name="parentNavigationLink">The parent navigation link which is being written around the entity reference link.</param> /// <param name="entityReferenceLink">The entity reference link to write.</param> protected override void WriteEntityReferenceInNavigationLinkContent(ODataNavigationLink parentNavigationLink, ODataEntityReferenceLink entityReferenceLink) { Debug.Assert(parentNavigationLink != null, "parentNavigationLink != null"); Debug.Assert(entityReferenceLink != null, "entityReferenceLink != null"); Debug.Assert(entityReferenceLink.Url != null, "We should have already verifies that the Url specified on the entity reference link is not null."); this.WriteNavigationLinkStart(parentNavigationLink, entityReferenceLink.Url); this.WriteNavigationLinkEnd(); }