/// <summary> /// Visits a payload element whose root is a DeferredLink. /// </summary> /// <param name="payloadElement">The root node of payload element being visited.</param> public void Visit(DeferredLink payloadElement) { ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); bool needsWrapping = this.isRootElement; this.isRootElement = false; if (needsWrapping) { this.writer.StartObjectScope(); this.writer.WriteName("uri"); this.writer.WriteString(payloadElement.UriString); } else { this.writer.StartObjectScope(); // __deferred is used for payloads generated by the server and sent to the client // __metadata is used if the client wants to update the navigation property // We are always using __metadata because the test framework is only used to generate // a payload on the client and sent them to the server. this.writer.WriteName("__metadata"); this.writer.StartObjectScope(); this.writer.WriteName("uri"); this.writer.WriteString(payloadElement.UriString); this.writer.EndScope(); this.writer.EndScope(); } if (needsWrapping) { this.writer.EndScope(); } }
/// <summary> /// Visits the payload element /// </summary> /// <param name="payloadElement">The payload element to visit</param> public override void Visit(DeferredLink payloadElement) { ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); ExceptionUtilities.CheckObjectNotNull(this.currentXElement, "Current XElement is not defined"); XElement linkElement; var navPropertyInstance = this.payloadStack.OfType <NavigationPropertyInstance>().FirstOrDefault(); if (navPropertyInstance == null) { linkElement = CreateMetadataElement(this.currentXElement, "ref"); CreateAtomAttribute(linkElement, "id", payloadElement.UriString ?? string.Empty); } else { string relAttributeValue; if (navPropertyInstance.AssociationLink == payloadElement) { relAttributeValue = DataServicesRelatedLinksNamespace + navPropertyInstance.Name; } else { relAttributeValue = DataServicesRelatedNamespace + navPropertyInstance.Name; } string contentType = payloadElement.Annotations.OfType <ContentTypeAnnotation>().Select(a => a.Value).SingleOrDefault(); string title = payloadElement.Annotations.OfType <TitleAnnotation>().Select(a => a.Value).SingleOrDefault(); linkElement = CreateAtomLinkElement(this.currentXElement, relAttributeValue, payloadElement.UriString, contentType, null, title); } PostProcessXElement(payloadElement, linkElement); }
private void AddFoldedLinksToEntityInsertPayload(DataServiceContextData contextData, EntityDescriptorData entityDescriptorData, EntityInstance payload) { var entityType = this.ModelSchema.EntityTypes.Single(t => t.FullName == entityDescriptorData.EntityClrType.FullName); foreach (var linkDescriptor in contextData.LinkDescriptorsData.Where(l => l.SourceDescriptor == entityDescriptorData)) { if (linkDescriptor.TargetDescriptor.State == EntityStates.Added) { continue; } var navigationProperty = entityType.AllNavigationProperties.Single(n => n.Name == linkDescriptor.SourcePropertyName); string contentType = MimeTypes.ApplicationAtomXml + ";type="; if (navigationProperty.ToAssociationEnd.Multiplicity == EndMultiplicity.Many) { contentType += "feed"; } else { contentType += "entry"; } // note: the edit-link is used rather than identity because the server needs to be able to query for the target entity // and the identity may not be an actual uri var link = new DeferredLink() { UriString = linkDescriptor.TargetDescriptor.EditLink.OriginalString } .WithContentType(contentType).WithTitleAttribute(linkDescriptor.SourcePropertyName); payload.Add(new NavigationPropertyInstance(linkDescriptor.SourcePropertyName, link)); } }
/// <summary> /// Creates a set of interesting entity reference link instances. /// </summary> /// <param name="settings">The test descriptor settings to use.</param> /// <returns>List of test descriptors with interesting entity reference link instances as payload.</returns> internal static IEnumerable <LinkCollection> CreateEntityReferenceLinksValues() { DeferredLink link1 = PayloadBuilder.DeferredLink("http://odata.org/deferred1"); DeferredLink link2 = PayloadBuilder.DeferredLink("http://odata.org/deferred2"); DeferredLink link3 = PayloadBuilder.DeferredLink("http://odata.org/deferred3"); yield return(PayloadBuilder.LinkCollection()); yield return(PayloadBuilder.LinkCollection().Item(link1)); yield return(PayloadBuilder.LinkCollection().Item(link1).Item(link2).Item(link3)); yield return(PayloadBuilder.LinkCollection().Item(link1).InlineCount(1)); yield return(PayloadBuilder.LinkCollection().Item(link1).InlineCount(-1)); yield return(PayloadBuilder.LinkCollection().Item(link1).NextLink("http://odata.org/nextlink")); yield return(PayloadBuilder.LinkCollection().Item(link1).InlineCount(1).NextLink("http://odata.org/nextlink")); yield return(PayloadBuilder.LinkCollection().Item(link1).Item(link2).Item(link3).InlineCount(1)); yield return(PayloadBuilder.LinkCollection().Item(link1).Item(link2).Item(link3).InlineCount(-1)); yield return(PayloadBuilder.LinkCollection().Item(link1).Item(link2).Item(link3).NextLink("http://odata.org/nextlink")); yield return(PayloadBuilder.LinkCollection().Item(link1).Item(link2).Item(link3).InlineCount(1).NextLink("http://odata.org/nextlink")); }
/// <summary> /// Visits the children of the given payload element and replaces it with a copy if any child changes /// </summary> /// <param name="payloadElement">The payload element to potentially replace</param> /// <returns>The original element or a copy to replace it with</returns> public virtual ODataPayloadElement Visit(NavigationPropertyInstance payloadElement) { ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); ODataPayloadElement replacedValue = null; if (payloadElement.Value != null) { replacedValue = this.Recurse(payloadElement.Value); } DeferredLink replacedAssociationLink = null; if (payloadElement.AssociationLink != null) { replacedAssociationLink = (DeferredLink)this.Recurse(payloadElement.AssociationLink); } if (!this.ShouldReplace(payloadElement.Value, replacedValue) && !this.ShouldReplace(payloadElement.AssociationLink, replacedAssociationLink)) { return(payloadElement); } return(payloadElement.ReplaceWith(new NavigationPropertyInstance(payloadElement.Name, replacedValue, replacedAssociationLink))); }
/// <summary> /// Verify the relationship link is as expected. /// </summary> /// <param name="navigation">navigation property instance for the navigation link</param> /// <param name="associationLink">relationship link to verify</param> /// <param name="expectedAssociationUri">expected link value</param> /// <param name="request">The request needed for error report.</param> /// <param name="response">The response to check the content type.</param> private void VerifyAssociationLink(NavigationPropertyInstance navigation, DeferredLink associationLink, string expectedAssociationUri, ODataRequest request, ODataResponse response) { bool linkShouldBeNull = false; if (!this.IsAtomResponse(response) && navigation.IsExpanded) { var expandedValue = ((ExpandedLink)navigation.Value).ExpandedElement; linkShouldBeNull = expandedValue == null; } if (linkShouldBeNull) { // json navigations are null, then there are no links if (associationLink != null) { this.Logger.WriteLine(LogLevel.Verbose, CultureInfo.InvariantCulture, "Expected association link == null, observed '{0}'", associationLink.UriString); this.ReportFailure(request, response); throw new ResponseVerificationException(); } } else { this.VerifyLinkUriValue(associationLink.UriString, expectedAssociationUri, request, response); // extra verifications for atom payload if (this.IsAtomResponse(response)) { this.VerifyAtomAssociationLinkTypeAttribute(associationLink, request, response); this.VerifyAtomTitleAttribute(navigation, associationLink, request, response); } } }
public void EntityReferenceLinkReadingNullUriTest() { EdmModel model = (EdmModel)Microsoft.Test.OData.Utils.Metadata.TestModels.BuildTestModel(); model.Fixup(); DeferredLink link = PayloadBuilder.DeferredLink(/*uri*/ null); this.CombinatorialEngineProvider.RunCombinations( baseUriValues, this.ReaderTestConfigurationProvider.AtomFormatConfigurations.Where(tc => !tc.IsRequest), (baseUriValue, testConfiguration) => { // NOTE: In JSON, the value of the 'uri' property will be 'null' which is not allowed (and we expect an error) // In ATOM, the HREF of an entity reference link is stored as element content and will thus be read as // string.Empty even if the source link was null NullUriValueTestCase <DeferredLink> testCase = new NullUriValueTestCase <DeferredLink> { SetNullUriAction = (instance, uri, testConfig) => instance.UriString = null, SetExpectedUriAction = (instance, uri, testConfig) => instance.UriString = UriToString(uri), }; this.RunNullUriReadingTest(link, testCase, model, baseUriValue, testConfiguration); }); }
/// <summary> /// Visits a DeferredLink, if IncludeRelationshipLinks = true then this will be a V3 payload /// </summary> /// <param name="payloadElement">payload Element</param> public override void Visit(DeferredLink payloadElement) { ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); this.IncreaseVersionIfIncludeRelationshipLinksIsTrue(payloadElement); base.Visit(payloadElement); }
private static void AddLinkMetadata(DeferredLink payloadElement, ODataNavigationLink link) { AtomLinkMetadata metadata = CreateLinkMetadata(payloadElement.Annotations.OfType <XmlTreeAnnotation>()); if (metadata != null) { link.SetAnnotation <AtomLinkMetadata>(metadata); } }
/// <summary> /// Visits the payload element and annotates it with metadata /// </summary> /// <param name="payloadElement">The payload element to visit</param> public override void Visit(DeferredLink payloadElement) { ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); var navigation = this.MetadataStack.OfType <NavigationProperty>().FirstOrDefault(); ExceptionUtilities.CheckObjectNotNull(navigation, "No navigation property found on metadata stack"); payloadElement.AddAnnotationIfNotExist(new NavigationPropertyAnnotation() { Property = navigation }); }
/// <summary> /// Visits a payload element whose root is a DeferredLink. /// </summary> /// <param name="payloadElement">The root node of the payload element being visited.</param> public override void Visit(DeferredLink payloadElement) { base.Visit(payloadElement); if (!this.requestPayload || this.depth > 2) { // Any deferred link inside a navigation link needs to be annotated (request/response payload differs) // Top level response payloads need to be annotated as they serialize differently in JSON-L this.AddVersionAnnotation(payloadElement); } }
/// <summary> /// Visits the children of the given payload element and replaces it with a copy if any child changes /// </summary> /// <param name="payloadElement">The payload element to potentially replace</param> /// <returns>The original element or a copy to replace it with</returns> public virtual ODataPayloadElement Visit(DeferredLink payloadElement) { ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); if (this.alwaysReplace) { return(payloadElement.ReplaceWith <DeferredLink>(new DeferredLink() { UriString = payloadElement.UriString })); } return(payloadElement); }
/// <summary> /// Computes the XmlTreeAnnotation for an association link. /// </summary> /// <param name="associationLink">The association link to compute the stream property for.</param> /// <returns>The <see cref="XmlTreeAnnotation"/> for the link specified in <paramref name="associationLink"/>.</returns> private XmlTreeAnnotation GetAssociationLinkXmlTreeAnnotation(DeferredLink associationLink) { if (associationLink == null) { return(null); } // Add all the attributes that are already stored on the association link as annotations List <XmlTreeAnnotation> attributes = new List <XmlTreeAnnotation>(); attributes.AddRange(associationLink.Annotations.OfType <XmlTreeAnnotation>().Where(a => a.IsAttribute)); return(XmlTreeAnnotation.Atom(TestAtomConstants.AtomLinkElementName, null, attributes.ToArray())); }
/// <summary> /// Initializes an ODataNestedResourceInfo 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); ODataNestedResourceInfo 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); this.writer.WriteStart(navigationLink); base.Visit(payloadElement); this.writer.WriteEnd(); }
/// <summary> /// Initializes an ODataNestedResourceInfo instance for the deferred link payload. /// </summary> /// <param name="payloadElement">The deferred link to process.</param> public override void Visit(DeferredLink payloadElement) { if (this.items.Peek() is ODataNestedResourceInfo) { ODataNestedResourceInfo navigationLink = (ODataNestedResourceInfo)this.items.Pop(); navigationLink.Url = new Uri(payloadElement.UriString); var contentType = payloadElement.Annotations.Where(a => a is ContentTypeAnnotation).SingleOrDefault(); if (contentType != null) { navigationLink.IsCollection = contentType.StringRepresentation.Contains("feed"); } var entry = (ODataResource)this.items.Peek(); var annotation = entry.GetAnnotation <ODataEntryNavigationLinksObjectModelAnnotation>(); if (annotation == null) { annotation = new ODataEntryNavigationLinksObjectModelAnnotation(); entry.SetAnnotation <ODataEntryNavigationLinksObjectModelAnnotation>(annotation); } annotation.Add(navigationLink, this.currentPropertyPosition); this.items.Push(navigationLink); if (!this.response) { navigationLink.SetAnnotation(new ODataNavigationLinkExpandedItemObjectModelAnnotation() { ExpandedItem = new ODataEntityReferenceLink() { Url = navigationLink.Url } }); } base.Visit(payloadElement); this.currentPropertyPosition++; } else { this.items.Push(new ODataEntityReferenceLink() { Url = new Uri(payloadElement.UriString) }); } }
/// <summary> /// Normalizes navigation property specific atom metadata. /// </summary> /// <param name="payloadElement">The payload element to normalize.</param> public override void Visit(NavigationPropertyInstance payloadElement) { DeferredLink deferredLink = payloadElement.Value as DeferredLink; if (deferredLink != null) { // If there is a type annotation specified as a XmlTreeAnnotion, copy its value over to a ContentTypeAnnotation as well. XmlTreeAnnotation typeAnnotation = deferredLink.Annotations.OfType <XmlTreeAnnotation>().SingleOrDefault(a => a.LocalName == TestAtomConstants.AtomLinkTypeAttributeName); if (typeAnnotation != null) { deferredLink.WithContentType(typeAnnotation.PropertyValue); } } base.Visit(payloadElement); }
/// <summary> /// Sets the expected navigation property for a top-level entity reference link. /// </summary> /// <param name="entityReferenceLink">The entity reference link instance to set the expected navigation property for.</param> /// <param name="owningType">The type owning the expected property.</param> /// <param name="navigationPropertyName">The name of the navigation property to set as the expected property.</param> /// <returns>The <paramref name="entityReferenceLink"/> after its expected property was set.</returns> public static DeferredLink ExpectedNavigationProperty( this DeferredLink entityReferenceLink, EntitySet entitySet, EntityType owningType, string navigationPropertyName) { ExceptionUtilities.CheckArgumentNotNull(entityReferenceLink, "entityReferenceLink"); ExceptionUtilities.CheckArgumentNotNull(owningType, "owningType"); ExceptionUtilities.CheckStringArgumentIsNotNullOrEmpty(navigationPropertyName, "navigationPropertyName"); ExpectedTypeODataPayloadElementAnnotation annotation = AddExpectedTypeAnnotation(entityReferenceLink); annotation.EntitySet = entitySet; annotation.OwningType = owningType; annotation.NavigationProperty = owningType.GetNavigationProperty(navigationPropertyName); return(entityReferenceLink); }
/// <summary> /// Visits a payload element whose root is a DeferredLink. /// </summary> /// <param name="expected">The root node of payload element being visited.</param> public void Visit(DeferredLink expected) { ExceptionUtilities.CheckArgumentNotNull(expected, "expected"); var observed = this.GetNextObservedElement <DeferredLink>(); using (this.Assert.WithMessage("Deferred link did not match expectation")) { if (this.comparingJsonLightResponse && expected.UriString == null) { this.Assert.IsNotNull(observed.UriString, "Conventional template evaluation should compute the Uri string of the deferred link."); } else { this.Assert.AreEqual(expected.UriString, observed.UriString, "Uri string did not match expectation"); } this.CompareAnnotations(expected.Annotations, observed.Annotations); } }
public void EntityReferenceLinkReadingBaseUriTest() { EdmModel model = (EdmModel)Microsoft.Test.OData.Utils.Metadata.TestModels.BuildTestModel(); model.Fixup(); DeferredLink link = PayloadBuilder.DeferredLink("http://odata.org/dummy"); this.CombinatorialEngineProvider.RunCombinations( payloadUris, baseUriValues, resolvers, new bool[] { false, true }, this.ReaderTestConfigurationProvider.AtomFormatConfigurations.Where(tc => !tc.IsRequest), (payloadUri, baseUriValue, resolver, runInBatch, testConfiguration) => { Action <DeferredLink, Uri, ReaderTestConfiguration> setLinkAction = (instance, uri, testConfig) => instance.UriString = UriToString(uri); this.RunBaseUriReadingTest(link, setLinkAction, model, payloadUri, baseUriValue, resolver, testConfiguration, runInBatch); }); }
/// <summary> /// Visits an entity reference link collection. /// </summary> /// <param name="entityReferenceLinks">The entity reference link collection to visit.</param> protected override ODataPayloadElement VisitEntityReferenceLinks(ODataEntityReferenceLinks entityReferenceLinks) { ExceptionUtilities.CheckArgumentNotNull(entityReferenceLinks, "entityReferenceLinks"); LinkCollection linkCollection = PayloadBuilder.LinkCollection() .InlineCount(entityReferenceLinks.Count) .NextLink(entityReferenceLinks.NextPageLink == null ? null : entityReferenceLinks.NextPageLink.OriginalString); IEnumerable <ODataEntityReferenceLink> links = entityReferenceLinks.Links; if (links != null) { foreach (ODataEntityReferenceLink link in links) { DeferredLink deferredLink = (DeferredLink)this.Visit(link); linkCollection.Add(deferredLink); } } return(linkCollection); }
private bool TryGetLink(JsonObject jsonObject, out ODataPayloadElement elem) { elem = null; // if this object has exactly one property with key "uri" // Example: // { // "uri": "http://services.odata.org/OData/OData.svc/Products(0)" // }, // return DeferredLink if (jsonObject.Properties.Count() == 1 && jsonObject.Properties.Single().Name == UriFieldName) { elem = new DeferredLink() { UriString = ((JsonPrimitiveValue)jsonObject.Properties.Single().Value).Value as string, }; return(true); } return(false); }
/// <summary> /// Visits a navigation link item. /// </summary> /// <param name="navigationLink">The navigation link to visit.</param> /// <returns>An ODataPayloadElement representing the navigation link.</returns> protected override ODataPayloadElement VisitNavigationLink(ODataNavigationLink navigationLink) { ExceptionUtilities.CheckArgumentNotNull(navigationLink, "navigationLink"); NavigationPropertyInstance navigationProperty = (NavigationPropertyInstance)base.VisitNavigationLink(navigationLink); // In ATOM even deferred links may know if they point to collection or singleton. // So add the content type annotation to them (through it IsCollection) so that comparison is precise. DeferredLink deferredLink = navigationProperty.Value as DeferredLink; if (deferredLink != null && navigationLink.IsCollection.HasValue) { deferredLink.IsCollection(navigationLink.IsCollection.Value); } AtomLinkMetadata atomMetadata = navigationLink.GetAnnotation <AtomLinkMetadata>(); if (atomMetadata != null && deferredLink != null) { ConvertAtomLinkChildrenMetadata(atomMetadata, navigationProperty.Value); } return(navigationProperty); }
/// <summary> /// Visits a payload element whose root is a DeferredLink. /// </summary> /// <param name="payloadElement">The root node of the payload element being visited.</param> public override void Visit(DeferredLink payloadElement) { base.Visit(payloadElement); if (this.CurrentElementIsRoot() && payloadElement.GetAnnotation <JsonLightContextUriAnnotation>() == null) { var expectedTypeAnnotation = payloadElement.GetAnnotation <ExpectedTypeODataPayloadElementAnnotation>(); if (expectedTypeAnnotation == null) { // Any navigation property in the model should suffice for generating the context uri because there is no // type information in the link. if (this.testDescriptor.PayloadEdmModel != null) { IEdmEntityType edmEntityTypeWithNavProps = this.testDescriptor.PayloadEdmModel.EntityTypes().FirstOrDefault(e => e.NavigationProperties().Any()); ExceptionUtilities.CheckObjectNotNull(edmEntityTypeWithNavProps, "No navigation properties found in the model"); IEdmNavigationProperty edmNavProperty = edmEntityTypeWithNavProps.NavigationProperties().First(); payloadElement.AddAnnotation(new ExpectedTypeODataPayloadElementAnnotation { EdmOwningType = edmEntityTypeWithNavProps, EdmNavigationProperty = edmNavProperty }); } } } }
/// <summary> /// Visits a navigation link item. /// </summary> /// <param name="navigationLink">The navigation link to visit.</param> protected override ODataPayloadElement VisitNavigationLink(ODataNestedResourceInfo navigationLink) { ExceptionUtilities.CheckArgumentNotNull(navigationLink, "navigationLink"); ODataPayloadElement navigationPropertyContent = null; // check whether there is an entry or feed associated with the link var expandedItemAnnotation = navigationLink.GetAnnotation <ODataNavigationLinkExpandedItemObjectModelAnnotation>(); if (expandedItemAnnotation != null) { string navigationLinkUrlString = !this.payloadContainsIdentityMetadata || navigationLink.Url == null ? null : navigationLink.Url.OriginalString; if (expandedItemAnnotation.ExpandedItem is ODataResource) { navigationPropertyContent = new ExpandedLink(this.Visit((ODataResource)expandedItemAnnotation.ExpandedItem)) { UriString = navigationLinkUrlString }; } else if (expandedItemAnnotation.ExpandedItem is ODataResourceSet) { navigationPropertyContent = new ExpandedLink(this.Visit((ODataResourceSet)expandedItemAnnotation.ExpandedItem)) { UriString = navigationLinkUrlString }; } else if (expandedItemAnnotation.ExpandedItem is ODataEntityReferenceLink) { ExceptionUtilities.Assert(!this.response, "Entity reference links in navigation links can only appear in requests."); navigationPropertyContent = this.VisitEntityReferenceLink((ODataEntityReferenceLink)expandedItemAnnotation.ExpandedItem); } else if (expandedItemAnnotation.ExpandedItem is List <ODataItem> ) { ExceptionUtilities.Assert(!this.response, "Navigation links with multiple items in content can only appear in requests."); LinkCollection linkCollection = new LinkCollection(); foreach (ODataItem item in (List <ODataItem>)expandedItemAnnotation.ExpandedItem) { if (item is ODataResourceSet) { linkCollection.Add(new ExpandedLink(this.Visit((ODataResourceSet)item))); } else { ExceptionUtilities.Assert(item is ODataEntityReferenceLink, "Only feed and entity reference links can appear in navigation link content with multiple items."); linkCollection.Add(this.VisitEntityReferenceLink((ODataEntityReferenceLink)item)); } } navigationPropertyContent = linkCollection; } else { ExceptionUtilities.Assert(expandedItemAnnotation.ExpandedItem == null, "Only expanded entry, feed or null is allowed."); navigationPropertyContent = new ExpandedLink(new EntityInstance(null, true)) { UriString = navigationLinkUrlString }; } } else { ExceptionUtilities.Assert(this.response, "Deferred links are only valid in responses."); // this is a deferred link DeferredLink deferredLink = new DeferredLink() { UriString = !this.payloadContainsIdentityMetadata || navigationLink.Url == null ? null : navigationLink.Url.OriginalString, }; navigationPropertyContent = deferredLink; } DeferredLink associationLink = null; if (this.payloadContainsIdentityMetadata && navigationLink.AssociationLinkUrl != null) { associationLink = new DeferredLink() { UriString = navigationLink.AssociationLinkUrl.OriginalString }; } return(new NavigationPropertyInstance(navigationLink.Name, navigationPropertyContent, associationLink)); }
/// <summary> /// Asserts that two payload elements are equal. /// </summary> /// <param name="expected">The expected element</param> /// <param name="observed">The actual, observed element</param> public void Compare(ODataPayloadElement expected, ODataPayloadElement observed) { if (expected == null) { this.Assert.IsNull(observed, "Observed element must be null"); return; } this.Assert.AreEqual(expected.ElementType, observed.ElementType, "Element types are not equal."); this.Assert.AreEqual(expected.Annotations.Count, observed.Annotations.Count, "Annotation counts are not equal"); Compare(expected.Annotations, observed.Annotations); switch (expected.ElementType) { case ODataPayloadElementType.EntitySetInstance: EntitySetInstance expectedSet = expected as EntitySetInstance; EntitySetInstance observedSet = observed as EntitySetInstance; this.Assert.AreEqual(expectedSet.NextLink, observedSet.NextLink, "Next links are not equal"); this.Assert.AreEqual(expectedSet.InlineCount, observedSet.InlineCount, "Inline counts are not equal"); this.Assert.AreEqual(expectedSet.Count, observedSet.Count, "Entity counts are not equal"); for (int i = 0; i < expectedSet.Count; i++) { Compare(expectedSet[i], observedSet[i]); } break; case ODataPayloadElementType.EntityInstance: EntityInstance expectedEntity = expected as EntityInstance; EntityInstance observedEntity = observed as EntityInstance; this.Assert.AreEqual(expectedEntity.Id, observedEntity.Id, "Entity IDs are not equal"); this.Assert.AreEqual(expectedEntity.ETag, observedEntity.ETag, "ETags are not equal"); this.Assert.AreEqual(expectedEntity.IsNull, observedEntity.IsNull, "IsNull flags are not equal"); this.Assert.AreEqual(expectedEntity.FullTypeName, observedEntity.FullTypeName, "FullTypeNames are not equal"); this.Assert.AreEqual(expectedEntity.StreamContentType, observedEntity.StreamContentType, "Stream content types are not equal"); this.Assert.AreEqual(expectedEntity.StreamEditLink, observedEntity.StreamEditLink, "Stream edit links are not equal"); this.Assert.AreEqual(expectedEntity.StreamETag, observedEntity.StreamETag, "Stream ETags are not equal"); this.Assert.AreEqual(expectedEntity.StreamSourceLink, observedEntity.StreamSourceLink, "Stream source links are not equal"); this.Assert.AreEqual(expectedEntity.Properties.Count(), observedEntity.Properties.Count(), "Property counts are not equal"); for (int i = 0; i < expectedEntity.Properties.Count(); i++) { Compare(expectedEntity.Properties.ElementAt(i), observedEntity.Properties.ElementAt(i)); } break; case ODataPayloadElementType.ComplexInstance: ComplexInstance expectedCI = expected as ComplexInstance; ComplexInstance observedCI = observed as ComplexInstance; this.Assert.AreEqual(expectedCI.IsNull, observedCI.IsNull, "IsNull flags are not equal"); this.Assert.AreEqual(expectedCI.FullTypeName, observedCI.FullTypeName, "Full type names are not equal"); this.Assert.AreEqual(expectedCI.Properties.Count(), observedCI.Properties.Count(), "Property counts are not equal"); for (int i = 0; i < expectedCI.Properties.Count(); i++) { Compare(expectedCI.Properties.ElementAt(i), observedCI.Properties.ElementAt(i)); } break; case ODataPayloadElementType.NamedStreamInstance: NamedStreamInstance expectedNsi = expected as NamedStreamInstance; NamedStreamInstance observedNsi = observed as NamedStreamInstance; this.Assert.AreEqual(expectedNsi.Name, observedNsi.Name, "Stream names are not equal"); this.Assert.AreEqual(expectedNsi.ETag, observedNsi.ETag, "Stream ETags are not equal"); this.Assert.AreEqual(expectedNsi.EditLink, observedNsi.EditLink, "Edit links are not equal"); this.Assert.AreEqual(expectedNsi.EditLinkContentType, observedNsi.EditLinkContentType, "Edit link content types are not equal"); this.Assert.AreEqual(expectedNsi.SourceLink, observedNsi.SourceLink, "Source links are not equal"); this.Assert.AreEqual(expectedNsi.SourceLinkContentType, observedNsi.SourceLinkContentType, "Source links content types are not equal"); break; case ODataPayloadElementType.NavigationPropertyInstance: NavigationPropertyInstance expectedNav = expected as NavigationPropertyInstance; NavigationPropertyInstance observedNav = observed as NavigationPropertyInstance; Assert.AreEqual(expectedNav.Name, observedNav.Name, "Navigation property names are not equal"); Compare(expectedNav.AssociationLink, observedNav.AssociationLink); Compare(expectedNav.Value, observedNav.Value); break; case ODataPayloadElementType.ComplexProperty: ComplexProperty expectedCP = expected as ComplexProperty; ComplexProperty observedCP = observed as ComplexProperty; this.Assert.AreEqual(expectedCP.Name, observedCP.Name, "Complex property names are not equal"); Compare(expectedCP.Value, observedCP.Value); break; case ODataPayloadElementType.PrimitiveProperty: PrimitiveProperty expectedProperty = expected as PrimitiveProperty; PrimitiveProperty observedProperty = observed as PrimitiveProperty; this.Assert.AreEqual(expectedProperty.Name, observedProperty.Name, "Primitive property names are not equal"); Compare(expectedProperty.Value, observedProperty.Value); break; case ODataPayloadElementType.PrimitiveValue: PrimitiveValue expectedValue = expected as PrimitiveValue; PrimitiveValue observedValue = observed as PrimitiveValue; this.Assert.AreEqual(expectedValue.IsNull, observedValue.IsNull, "IsNull flags are not equal"); if (expectedValue.FullTypeName != null) { if (expectedValue.FullTypeName.Equals("Edm.String")) { this.Assert.IsTrue(string.IsNullOrEmpty(observedValue.FullTypeName) || observedValue.FullTypeName.Equals("Edm.String"), "FullTypeName should be null or Edm.String"); } else { this.Assert.AreEqual(expectedValue.FullTypeName, observedValue.FullTypeName, "Full type names are not equal"); } } else { this.Assert.IsNull(observedValue.FullTypeName, "observed full type name should be null"); } this.Assert.AreEqual(expectedValue.ClrValue, observedValue.ClrValue, "Clr values are not equal"); break; case ODataPayloadElementType.DeferredLink: DeferredLink expectedLink = expected as DeferredLink; DeferredLink observedLink = observed as DeferredLink; this.Assert.AreEqual(expectedLink.UriString, observedLink.UriString, "Uris are not equal"); break; case ODataPayloadElementType.ExpandedLink: ExpandedLink expectedExpand = expected as ExpandedLink; ExpandedLink observedExpand = observed as ExpandedLink; Compare(expectedExpand.ExpandedElement, observedExpand.ExpandedElement); break; case ODataPayloadElementType.LinkCollection: LinkCollection expectedLinks = expected as LinkCollection; LinkCollection observedLinks = observed as LinkCollection; this.Assert.AreEqual(expectedLinks.Count, observedLinks.Count, "Link counts are not equal"); this.Assert.AreEqual(expectedLinks.InlineCount, observedLinks.InlineCount, "Link inline counts are not equal"); for (int i = 0; i < expectedLinks.Count; i++) { Compare(expectedLinks[i], observedLinks[i]); } break; case ODataPayloadElementType.PrimitiveMultiValueProperty: var expectedPrimitiveCollectionProperty = expected as PrimitiveMultiValueProperty; var observedPrimitiveCollectionProperty = observed as PrimitiveMultiValueProperty; this.Assert.AreEqual(expectedPrimitiveCollectionProperty.Name, observedPrimitiveCollectionProperty.Name, "Property names are not equal"); this.Assert.AreEqual(expectedPrimitiveCollectionProperty.Value.FullTypeName, observedPrimitiveCollectionProperty.Value.FullTypeName, "Full type names are not equal"); this.Assert.AreEqual(expectedPrimitiveCollectionProperty.Value.Count, observedPrimitiveCollectionProperty.Value.Count, "Collection counts are not equal"); for (int i = 0; i < expectedPrimitiveCollectionProperty.Value.Count; i++) { Compare(expectedPrimitiveCollectionProperty.Value[i], observedPrimitiveCollectionProperty.Value[i]); } break; case ODataPayloadElementType.ComplexMultiValueProperty: var expectedComplexCollectionProperty = expected as ComplexMultiValueProperty; var observedComplexCollectionProperty = observed as ComplexMultiValueProperty; this.Assert.AreEqual(expectedComplexCollectionProperty.Name, observedComplexCollectionProperty.Name, "Property names are not equal"); this.Assert.AreEqual(expectedComplexCollectionProperty.Value.FullTypeName, observedComplexCollectionProperty.Value.FullTypeName, "Full type names are not equal"); this.Assert.AreEqual(expectedComplexCollectionProperty.Value.Count, observedComplexCollectionProperty.Value.Count, "Collection counts are not equal"); for (int i = 0; i < expectedComplexCollectionProperty.Value.Count; i++) { Compare(expectedComplexCollectionProperty.Value[i], observedComplexCollectionProperty.Value[i]); } break; case ODataPayloadElementType.PrimitiveCollection: var expectedPrimitiveCollection = expected as PrimitiveCollection; var observedPrimitiveCollection = observed as PrimitiveCollection; this.Assert.AreEqual(expectedPrimitiveCollection.Count, observedPrimitiveCollection.Count, "Collection counts are not equal"); for (int i = 0; i < expectedPrimitiveCollection.Count; i++) { Compare(expectedPrimitiveCollection[i], observedPrimitiveCollection[i]); } break; case ODataPayloadElementType.ComplexInstanceCollection: var expectedComplexCollection = expected as ComplexInstanceCollection; var observedComplexCollection = observed as ComplexInstanceCollection; this.Assert.AreEqual(expectedComplexCollection.Count, observedComplexCollection.Count, "Collection counts are not equal"); for (int i = 0; i < expectedComplexCollection.Count; i++) { Compare(expectedComplexCollection[i], observedComplexCollection[i]); } break; case ODataPayloadElementType.NullPropertyInstance: case ODataPayloadElementType.EmptyUntypedCollection: break; default: this.Assert.Fail("Case " + expected.ElementType + " unhandled"); break; } }
public override void Visit(DeferredLink payloadElement) { base.Visit(payloadElement); payloadElement.RemoveAnnotations(typeof(ContentTypeAnnotation)); }
/// <summary> /// Visits the payload element and annotates it with metadata /// </summary> /// <param name="payloadElement">The payload element to visit</param> public override void Visit(DeferredLink payloadElement) { ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); var navigation = this.MetadataStack.OfType<NavigationProperty>().FirstOrDefault(); ExceptionUtilities.CheckObjectNotNull(navigation, "No navigation property found on metadata stack"); payloadElement.AddAnnotationIfNotExist(new NavigationPropertyAnnotation() { Property = navigation }); }
public void EntityReferenceLinksReaderAtomTest() { const string link1String = "http://odata.org/deferred1"; const string link2String = "http://odata.org/deferred2"; const string nextString = "http://odata.org/next"; DeferredLink link1 = PayloadBuilder.DeferredLink(link1String); DeferredLink link2 = PayloadBuilder.DeferredLink(link2String); #region Extra attributes on the <feed> element var linksElementPayloads = new[] { // extra attributes on <links> element without content new { PayloadElement = PayloadBuilder.LinkCollection(), Template = "<feed {0} />", }, // extra attributes on <m:count> element new { PayloadElement = PayloadBuilder.LinkCollection().InlineCount(1), Template = "<feed><m:count {0}>1</m:count></feed>", }, // extra attributes on <d:next> element new { PayloadElement = PayloadBuilder.LinkCollection().NextLink("http://odata.org/next"), Template = "<feed><d:next {0}>http://odata.org/next</d:next></feed>", }, }; string[] attributes = new string[] { "foo='bar'", "m:foo='bar'", "foo=''", "lang='invalid'", }; IEnumerable <PayloadReaderTestDescriptor> testDescriptors = linksElementPayloads.SelectMany(linkPayload => attributes.Select(attribute => { var payloadElement = linkPayload.PayloadElement.DeepCopy(); string xmlRep = string.Format(CultureInfo.InvariantCulture, linkPayload.Template, attribute); payloadElement = payloadElement.XmlRepresentation(xmlRep); return(new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = payloadElement, }); })); #endregion Extra attributes on the <links> element #region Extra padding between the elements var extraPaddingPayloads = new[] { new { PayloadElement = PayloadBuilder.LinkCollection(), Template = "<feed>{0}</feed>", }, new { PayloadElement = PayloadBuilder.LinkCollection().InlineCount(1), Template = "<feed>{0}<m:count>1</m:count></feed>", }, new { PayloadElement = PayloadBuilder.LinkCollection().InlineCount(1), Template = "<feed><m:count>1</m:count>{0}</feed>", }, new { PayloadElement = PayloadBuilder.LinkCollection().NextLink(nextString), Template = "<feed>{0}<d:next>http://odata.org/next</d:next></feed>", }, new { PayloadElement = PayloadBuilder.LinkCollection().NextLink(nextString), Template = "<feed><d:next>http://odata.org/next</d:next>{0}</feed>", }, new { PayloadElement = PayloadBuilder.LinkCollection().InlineCount(1).NextLink(nextString), Template = "<feed><m:count>1</m:count>{0}<d:next>http://odata.org/next</d:next></feed>", }, new { PayloadElement = PayloadBuilder.LinkCollection().Item(link1).InlineCount(1).NextLink(nextString), Template = "<feed><m:count>1</m:count>{0}<m:ref id =\"" + link1String + "\"/><d:next>" + nextString + "</d:next></feed>", }, new { PayloadElement = PayloadBuilder.LinkCollection().Item(link1).InlineCount(1).NextLink(nextString), Template = "<feed><m:count>1</m:count><m:ref id=\"" + link1String + "\"/>{0}<d:next>" + nextString + "</d:next></feed>", }, new { PayloadElement = PayloadBuilder.LinkCollection().Item(link1).Item(link2).InlineCount(2).NextLink(nextString), Template = "<feed><m:count>2</m:count><m:ref id=\"" + link1String + "\"/>{0}<m:ref id=\"" + link2String + "\"/><d:next>" + nextString + "</d:next></feed>", }, }; string[] xmlPaddingToIgnore = new string[] { string.Empty, // Nothing " \r\n\t", // Whitespace only "<!--s--> <?value?>", // Insignificant nodes "some text <![CDATA[cdata]]>", // Significant nodes to be ignored "<foo xmlns=''/>", // Element in no namespace "<c:foo xmlns:c='ref' attr='1'><c:child/>text</c:foo>", // Element in custom namespace "<d:properties/>", // Element in data namespace (should be ignored as well) "<entry/>", // Element in atom namespace (should also be ignored) }; IEnumerable <PayloadReaderTestDescriptor> extraPaddingTestDescriptors = extraPaddingPayloads.SelectMany(extraPaddingPayload => xmlPaddingToIgnore.Select(xmlPadding => { var payloadElement = extraPaddingPayload.PayloadElement.DeepCopy(); string xmlRep = string.Format(CultureInfo.InvariantCulture, extraPaddingPayload.Template, xmlPadding); payloadElement = payloadElement.XmlRepresentation(xmlRep); return(new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = payloadElement, }); })); testDescriptors = testDescriptors.Concat(extraPaddingTestDescriptors); #endregion Extra padding between the elements #region Extra elements in the <feed> content LinkCollection links = PayloadBuilder.LinkCollection() .InlineCount(2) .Item(PayloadBuilder.DeferredLink(link1String)) .Item(PayloadBuilder.DeferredLink(link2String)) .NextLink(nextString); XElement ref1Element = new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataRefElementName); ref1Element.SetAttributeValue(TestAtomConstants.AtomIdElementName, link1String); XElement ref2Element = new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataRefElementName); ref1Element.SetAttributeValue(TestAtomConstants.AtomIdElementName, link2String); XElement xmlRepresentation = new XElement(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomFeedElementName, new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataCountElementName, "2"), ref1Element, ref2Element, new XElement(TestAtomConstants.ODataXNamespace + TestAtomConstants.ODataNextLinkElementName, nextString)); XElement[] extraElements = new XElement[] { new XElement(XName.Get("foo"), "bar"), new XElement(XName.Get("foo"), new XElement(XName.Get("bar"))), new XElement(XName.Get("foo"), new XAttribute(XName.Get("bar"), "attribute-value")), new XElement(TestAtomConstants.ODataMetadataXNamespace + "foo", "bar"), new XElement(TestAtomConstants.ODataMetadataXNamespace + "foo", new XElement(TestAtomConstants.ODataMetadataXNamespace + "bar")), new XElement(XName.Get("foo"), new XAttribute(TestAtomConstants.ODataMetadataXNamespace + "bar", "attribute-value")), // "Ref" element in the OData metadaata namespace, should be ignored, "ref" is expected new XElement(TestAtomConstants.ODataMetadataXNamespace + "Ref"), // "uri" element in the OData namespace, should be ignored, OData metadata namespace is expected new XElement(TestAtomConstants.ODataXNamespace + "ref"), }; IEnumerable <PayloadReaderTestDescriptor> extraElementTestDescriptors = extraElements.SelectMany(extraElement => { return(InjectElement(extraElement, xmlRepresentation).Select(linksWithInjectedElement => new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = links.DeepCopy().XmlRepresentation(linksWithInjectedElement), } )); }); testDescriptors = testDescriptors.Concat(extraElementTestDescriptors); #endregion Extra elements in the <links> content #region Various payload orders for an error element links = PayloadBuilder.LinkCollection() .InlineCount(1) .Item(PayloadBuilder.DeferredLink(link1String)) .NextLink(nextString); ref1Element = new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataRefElementName); ref1Element.SetAttributeValue(TestAtomConstants.AtomIdElementName, link1String); xmlRepresentation = new XElement(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomFeedElementName, new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataCountElementName, "1"), ref1Element, new XElement(TestAtomConstants.ODataXNamespace + TestAtomConstants.ODataNextLinkElementName, nextString)); IEnumerable <PayloadReaderTestDescriptor> payloadOrderTestDescriptors = GeneratePayloadOrders(xmlRepresentation).Select(xmlRep => new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = links.DeepCopy().XmlRepresentation(xmlRep), } ); testDescriptors = testDescriptors.Concat(payloadOrderTestDescriptors); #endregion Various payload orders for an error element this.CombinatorialEngineProvider.RunCombinations( testDescriptors, this.ReaderTestConfigurationProvider.AtomFormatConfigurations, (testDescriptor, testConfiguration) => { testDescriptor.RunTest(testConfiguration); }); }
/// <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) { if (this.items.Peek() is ODataNavigationLink) { ODataNavigationLink navigationLink = (ODataNavigationLink)this.items.Pop(); navigationLink.Url = new Uri(payloadElement.UriString); AddLinkMetadata(payloadElement, navigationLink); var contentType = payloadElement.Annotations.Where(a => a is ContentTypeAnnotation).SingleOrDefault(); if (contentType != null) { navigationLink.IsCollection = contentType.StringRepresentation.Contains("feed"); } var entry = (ODataEntry)this.items.Peek(); var annotation = entry.GetAnnotation<ODataEntryNavigationLinksObjectModelAnnotation>(); if (annotation == null) { annotation = new ODataEntryNavigationLinksObjectModelAnnotation(); entry.SetAnnotation<ODataEntryNavigationLinksObjectModelAnnotation>(annotation); } annotation.Add(navigationLink, this.currentPropertyPosition); this.items.Push(navigationLink); if (!this.response) { navigationLink.SetAnnotation(new ODataNavigationLinkExpandedItemObjectModelAnnotation() { ExpandedItem = new ODataEntityReferenceLink() { Url = navigationLink.Url } }); } base.Visit(payloadElement); this.currentPropertyPosition++; } else { this.items.Push(new ODataEntityReferenceLink() { Url = new Uri(payloadElement.UriString) }); } }
/// <summary> /// Visits a payload element whose root is a DeferredLink. /// </summary> /// <param name="payloadElement">The root node of payload element being visited.</param> public void Visit(DeferredLink payloadElement) { ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); // if the link is deferred, there is no data to validate // TODO: add mising verification var originalXmlPayloadElementAnnotation = payloadElement.Annotations.OfType<XmlPayloadElementRepresentationAnnotation>().SingleOrDefault(); if (originalXmlPayloadElementAnnotation != null) { // Validate that the namespace used is not the metadata namespace var element = (XElement)originalXmlPayloadElementAnnotation.XmlNodes.Single(); this.parent.Assert.AreEqual(element.Name.Namespace.NamespaceName, ODataConstants.DataServicesNamespaceName, "Producing uri in Metadata Namespace is invalid OData"); } }
/// <summary> /// Visits a payload element whose root is a DeferredLink. /// </summary> /// <param name="payloadElement">The root node of the payload element being visited.</param> public override void Visit(DeferredLink payloadElement) { base.Visit(payloadElement); if (this.CurrentElementIsRoot() && payloadElement.GetAnnotation<JsonLightContextUriAnnotation>() == null) { var expectedTypeAnnotation = payloadElement.GetAnnotation<ExpectedTypeODataPayloadElementAnnotation>(); if (expectedTypeAnnotation == null) { // Any navigation property in the model should suffice for generating the context uri because there is no // type information in the link. if (this.testDescriptor.PayloadEdmModel != null) { IEdmEntityType edmEntityTypeWithNavProps = this.testDescriptor.PayloadEdmModel.EntityTypes().FirstOrDefault(e => e.NavigationProperties().Any()); ExceptionUtilities.CheckObjectNotNull(edmEntityTypeWithNavProps, "No navigation properties found in the model"); IEdmNavigationProperty edmNavProperty = edmEntityTypeWithNavProps.NavigationProperties().First(); payloadElement.AddAnnotation(new ExpectedTypeODataPayloadElementAnnotation { EdmOwningType = edmEntityTypeWithNavProps, EdmNavigationProperty = edmNavProperty }); } } } }
private bool TryGetEntityInstance(JsonObject jsonObject, out ODataPayloadElement elem) { string uri = this.GetMetadataPropertyValue(jsonObject, UriFieldName); string id = this.GetMetadataPropertyValue(jsonObject, IdFieldName); string typeName = this.GetMetadataPropertyValue(jsonObject, TypeFieldName); string etag = this.GetMetadataPropertyValue(jsonObject, ETagFieldName); string streamSrc = this.GetMetadataPropertyValue(jsonObject, MediaSrcFieldName); string streamEdit = this.GetMetadataPropertyValue(jsonObject, EditMediaFieldName); string streamEtag = this.GetMetadataPropertyValue(jsonObject, MediaETagFieldName); string contentType = this.GetMetadataPropertyValue(jsonObject, ContentTypeFieldName); List <ServiceOperationDescriptor> actions = null; bool containsActionsMetadata = this.TryGetServiceOperationDescriptorAnnotations(jsonObject, "actions", out actions); List <ServiceOperationDescriptor> functions = null; bool containsFunctionMetadata = this.TryGetServiceOperationDescriptorAnnotations(jsonObject, "functions", out functions); // if this object has any property with key "__deferred" // or metadata tag returns a "uri", "id", or "etag" property, // or actions, or functions // return EntityInstance // else return ComplexInstance bool isEntity = this.ContainsDeferredLink(jsonObject); isEntity |= uri != null; isEntity |= id != null; isEntity |= etag != null; isEntity |= containsActionsMetadata; isEntity |= containsFunctionMetadata; if (isEntity) { EntityInstance entity = new EntityInstance(typeName, false, id, etag); if (containsActionsMetadata) { foreach (var action in actions) { entity.ServiceOperationDescriptors.Add(action); } } if (containsFunctionMetadata) { foreach (var function in functions) { entity.ServiceOperationDescriptors.Add(function); } } entity.EditLink = uri; entity.StreamSourceLink = streamSrc; entity.StreamEditLink = streamEdit; entity.StreamETag = streamEtag; entity.StreamContentType = contentType; foreach (JsonProperty prop in jsonObject.Properties) { if (prop.Name != MetadataFieldName && prop.Name != LinkInfoFieldName) { entity.Add(this.ConvertProperty(prop) as PropertyInstance); } } // Update entity navigation properties with association links JsonObject metaDataJsonObject = (JsonObject)jsonObject.Properties.Single(p1 => p1.Name == MetadataFieldName).Value; JsonProperty properties = metaDataJsonObject.Properties.FirstOrDefault(p2 => p2.Name == PropertiesFieldName); if (properties != null) { foreach (JsonProperty jp in ((JsonObject)properties.Value).Properties) { JsonProperty associationUriJsonProperty = ((JsonObject)jp.Value).Properties.SingleOrDefault(p => p.Name == AssociationUriFieldName); DeferredLink newAssociationLink = new DeferredLink(); if (associationUriJsonProperty != null) { newAssociationLink.UriString = ((JsonPrimitiveValue)associationUriJsonProperty.Value).Value as string; } var navigation = entity.Properties.SingleOrDefault(np => np.Name.Equals(jp.Name)); NavigationPropertyInstance navigationPropertyInstance = navigation as NavigationPropertyInstance; if (navigationPropertyInstance != null) { navigationPropertyInstance.AssociationLink = newAssociationLink; } else if (navigation is EmptyCollectionProperty) { ExpandedLink newExpandedLink = new ExpandedLink() { ExpandedElement = new EntitySetInstance() }; NavigationPropertyInstance newNavigation = new NavigationPropertyInstance(navigation.Name, newExpandedLink, newAssociationLink); entity.Replace(navigation, newNavigation); } else { ExceptionUtilities.Assert(navigation.ElementType == ODataPayloadElementType.NullPropertyInstance, "Invalid type of PropertyInstance : {0}", navigation.ElementType); ExpandedLink newExpandedLink = new ExpandedLink() { ExpandedElement = new EntityInstance() }; NavigationPropertyInstance newNavigation = new NavigationPropertyInstance(navigation.Name, newExpandedLink, newAssociationLink); entity.Replace(navigation, newNavigation); } } } elem = entity; return(true); } elem = null; return(false); }
/// <summary> /// Computes the XmlTreeAnnotation for an association link. /// </summary> /// <param name="associationLink">The association link to compute the stream property for.</param> /// <returns>The <see cref="XmlTreeAnnotation"/> for the link specified in <paramref name="associationLink"/>.</returns> private XmlTreeAnnotation GetAssociationLinkXmlTreeAnnotation(DeferredLink associationLink) { if (associationLink == null) { return null; } // Add all the attributes that are already stored on the association link as annotations List<XmlTreeAnnotation> attributes = new List<XmlTreeAnnotation>(); attributes.AddRange(associationLink.Annotations.OfType<XmlTreeAnnotation>().Where(a => a.IsAttribute)); return XmlTreeAnnotation.Atom(TestAtomConstants.AtomLinkElementName, null, attributes.ToArray()); }
/// <summary> /// Converts the given name/value pair into a property element. /// And infers the type of property from the converted value. /// </summary> /// <param name="jsonProperty">the property value</param> /// <returns>the converted property</returns> private PropertyInstance ConvertProperty(JsonProperty jsonProperty) { if (jsonProperty.Value.JsonType == JsonValueType.JsonPrimitiveValue && ((JsonPrimitiveValue)jsonProperty.Value).Value == null) { return(new NullPropertyInstance() { Name = jsonProperty.Name }); } else { ODataPayloadElement elem = this.ConvertValue(jsonProperty.Value); ExceptionUtilities.CheckObjectNotNull(elem, "Converted property value was null"); if (elem.ElementType == ODataPayloadElementType.PrimitiveValue) { return(new PrimitiveProperty(jsonProperty.Name, (PrimitiveValue)elem)); } else if (elem.ElementType == ODataPayloadElementType.ComplexInstance) { return(new ComplexProperty(jsonProperty.Name, (ComplexInstance)elem)); } else if (elem.ElementType == ODataPayloadElementType.EntityInstance) { return(new NavigationPropertyInstance(jsonProperty.Name, new ExpandedLink(elem))); } else if (elem.ElementType == ODataPayloadElementType.DeferredLink) { DeferredLink deferredLink = (DeferredLink)elem; return(new NavigationPropertyInstance(jsonProperty.Name, deferredLink)); } else if (elem.ElementType == ODataPayloadElementType.EntitySetInstance) { return(new NavigationPropertyInstance(jsonProperty.Name, elem)); } else if (elem.ElementType == ODataPayloadElementType.ComplexMultiValue) { ComplexMultiValue complexMultiValue = (ComplexMultiValue)elem; return(new ComplexMultiValueProperty(jsonProperty.Name, complexMultiValue)); } else if (elem.ElementType == ODataPayloadElementType.PrimitiveMultiValue) { PrimitiveMultiValue primitiveMultiValue = (PrimitiveMultiValue)elem; return(new PrimitiveMultiValueProperty(jsonProperty.Name, primitiveMultiValue)); } else if (elem.ElementType == ODataPayloadElementType.ComplexInstanceCollection) { ComplexInstanceCollection complexCollection = (ComplexInstanceCollection)elem; return(new ComplexMultiValueProperty(jsonProperty.Name, new ComplexMultiValue(null, false, complexCollection.ToArray()))); } else if (elem.ElementType == ODataPayloadElementType.PrimitiveCollection) { PrimitiveCollection primitiveCollection = (PrimitiveCollection)elem; return(new PrimitiveMultiValueProperty(jsonProperty.Name, new PrimitiveMultiValue(null, false, primitiveCollection.ToArray()))); } else if (elem.ElementType == ODataPayloadElementType.NamedStreamInstance) { NamedStreamInstance nsi = (NamedStreamInstance)elem; nsi.Name = jsonProperty.Name; return(nsi); } else { ExceptionUtilities.Assert(elem.ElementType == ODataPayloadElementType.EmptyUntypedCollection, "Do not know how to handle element of type" + elem.ElementType); return(new EmptyCollectionProperty(jsonProperty.Name, (EmptyUntypedCollection)elem)); } } }
/// <summary> /// Deserialize a single link /// </summary> /// <param name="link">the xml representing the link</param> /// <returns>Either an expanded or deferred link</returns> private ODataPayloadElement DeserializeLink(XElement link) { if (link.Name == MetadataUri) { var result = new DeferredLink() { UriString = link.Attribute(AtomId).Value }; AddXmlBaseAnnotation(result, link); // add the element so that later validation can happen to validate the MetadataUri namespace is not used var xmlPayloadRep = new XmlPayloadElementRepresentationAnnotation() { XmlNodes = new XNode[] { link } }; result.Annotations.Add(xmlPayloadRep); return(result); } string hrefValue = null; XAttribute hrefAttribute = link.Attribute(Href); if (hrefAttribute != null) { if (string.IsNullOrEmpty(hrefAttribute.Value)) { // special case: navigation properties with null values are represented as empty href tags return(null); } hrefValue = hrefAttribute.Value; } // if the link has an inline element, assume it is expanded XElement inline = link.Element(MetadataInline); if (inline != null) { // deserialize the expanded element ExpandedLink expanded = new ExpandedLink() { UriString = hrefValue }; if (inline.HasElements) { expanded.ExpandedElement = this.ConvertToPayloadElement(inline.Elements().Single()); } this.AddLinkAttributes(expanded, link); return(expanded); } else { // otherwise it must be deferred DeferredLink deferred = new DeferredLink() { UriString = hrefValue }; this.AddLinkAttributes(deferred, link); return(deferred); } }
/// <summary> /// Visits the payload element /// </summary> /// <param name="payloadElement">The payload element to visit</param> public virtual void Visit(DeferredLink payloadElement) { ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); }
/// <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(); }
private static void AddLinkMetadata(DeferredLink payloadElement, ODataNavigationLink link) { AtomLinkMetadata metadata = CreateLinkMetadata(payloadElement.Annotations.OfType<XmlTreeAnnotation>()); if (metadata != null) { link.SetAnnotation<AtomLinkMetadata>(metadata); } }
/// <summary> /// Deserialize a single link /// </summary> /// <param name="link">the xml representing the link</param> /// <returns>Either an expanded or deferred link</returns> private ODataPayloadElement DeserializeLink(XElement link) { if (link.Name == MetadataUri) { var result = new DeferredLink() { UriString = link.Attribute(AtomId).Value }; AddXmlBaseAnnotation(result, link); // add the element so that later validation can happen to validate the MetadataUri namespace is not used var xmlPayloadRep = new XmlPayloadElementRepresentationAnnotation() { XmlNodes = new XNode[] { link } }; result.Annotations.Add(xmlPayloadRep); return result; } string hrefValue = null; XAttribute hrefAttribute = link.Attribute(Href); if (hrefAttribute != null) { if (string.IsNullOrEmpty(hrefAttribute.Value)) { // special case: navigation properties with null values are represented as empty href tags return null; } hrefValue = hrefAttribute.Value; } // if the link has an inline element, assume it is expanded XElement inline = link.Element(MetadataInline); if (inline != null) { // deserialize the expanded element ExpandedLink expanded = new ExpandedLink() { UriString = hrefValue }; if (inline.HasElements) { expanded.ExpandedElement = this.ConvertToPayloadElement(inline.Elements().Single()); } this.AddLinkAttributes(expanded, link); return expanded; } else { // otherwise it must be deferred DeferredLink deferred = new DeferredLink() { UriString = hrefValue }; this.AddLinkAttributes(deferred, link); return deferred; } }