Esempio n. 1
0
        /// <summary>
        /// Initializes a new expanded ODataNestedResourceInfo instance and visits the payload.
        /// </summary>
        /// <param name="payloadElement">The expanded link to visit.</param>
        public override void Visit(ExpandedLink payloadElement)
        {
            Debug.Assert(this.items.Peek() is ODataNestedResourceInfo);
            ODataNestedResourceInfo navigationLink = (ODataNestedResourceInfo)this.items.Pop();

            navigationLink.IsCollection = !payloadElement.IsSingleEntity;
            // TODO, ckerer: where do I get the info whether this links is a singleton or collection?
            if (payloadElement.UriString != null)
            {
                navigationLink.Url = new Uri(payloadElement.UriString);
            }

            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);
            base.Visit(payloadElement);
            this.currentPropertyPosition++;
        }
        /// <summary>
        /// Visits the payload element
        /// </summary>
        /// <param name="payloadElement">The payload element to visit</param>
        public override void Visit(ExpandedLink payloadElement)
        {
            var navPropertyInstance = this.payloadStack.OfType <NavigationPropertyInstance>().FirstOrDefault();

            ExceptionUtilities.CheckObjectNotNull(navPropertyInstance, "No NavigationPropertyInstance found in stack for ExpandedLink");

            string contentType           = null;
            var    contentTypeAnnotation = payloadElement.Annotations.OfType <ContentTypeAnnotation>().SingleOrDefault();

            if (contentTypeAnnotation != null)
            {
                contentType = contentTypeAnnotation.Value;
            }
            else if (payloadElement.ExpandedElement != null)
            {
                contentType = MimeTypes.ApplicationAtomXml + ";type=" + (payloadElement.IsSingleEntity ? "entry" : "feed");
            }

            XElement linkElement = CreateAtomLinkElement(
                this.currentXElement,
                DataServicesRelatedNamespace + navPropertyInstance.Name,
                payloadElement.UriString,
                contentType);

            XElement inlineElement = CreateMetadataElement(linkElement, "inline");

            if (payloadElement.ExpandedElement != null)
            {
                this.VisitPayloadElement(payloadElement.ExpandedElement, inlineElement);
            }

            PostProcessXElement(payloadElement, linkElement);
        }
            /// <summary>
            /// Visits a payload element whose root is an ExpandedLink.
            /// </summary>
            /// <param name="expected">The root node of payload element being visited.</param>
            public void Visit(ExpandedLink expected)
            {
                ExceptionUtilities.CheckArgumentNotNull(expected, "expected");
                var observed = this.GetNextObservedElement <ExpandedLink>();

                using (this.Assert.WithMessage("Expanded link did not match expectation"))
                {
                    if (expected.ExpandedElement == null)
                    {
                        this.Assert.IsNull(observed.ExpandedElement, "Value unexpectedly non-null");
                        this.CompareAnnotations(expected.Annotations, observed.Annotations);
                    }
                    else
                    {
                        this.Assert.IsNotNull(observed.ExpandedElement, "Value unexpectedly null");
                        this.CompareAnnotations(expected.Annotations, observed.Annotations);
                        this.WrapAccept(expected.ExpandedElement, observed.ExpandedElement);
                    }

                    if (this.comparingJsonLightResponse && expected.UriString == null)
                    {
                        this.Assert.IsNotNull(observed.UriString, "Conventional template evaluation should compute the Uri string of the expanded link.");
                    }
                    else
                    {
                        this.Assert.AreEqual(expected.UriString, observed.UriString, "Uri string did not match expectation");
                    }
                }
            }
Esempio n. 4
0
        /// <summary>
        /// Visits the payload element
        /// </summary>
        /// <param name="payloadElement">The payload element to visit</param>
        public virtual void Visit(ExpandedLink payloadElement)
        {
            ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");

            if (payloadElement.ExpandedElement != null)
            {
                this.Recurse(payloadElement.ExpandedElement);
            }
        }
        /// <summary>
        /// Normalizes an expanded link.
        /// </summary>
        /// <param name="payloadElement">The payload element to normalize.</param>
        public override void Visit(ExpandedLink payloadElement)
        {
            base.Visit(payloadElement);

            // Expanded link Url is only writtern for responses.
            if (this.testConfiguration.IsRequest)
            {
                payloadElement.UriString = null;
            }
        }
Esempio n. 6
0
 /// <summary>
 /// Visits the payload element
 /// </summary>
 /// <param name="payloadElement">The payload element to visit</param>
 public override void Visit(ExpandedLink payloadElement)
 {
     ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");
     var annotation = payloadElement.Annotations.Where(a => a is NavigationPropertyAnnotation).SingleOrDefault();
     payloadElement.Annotations.Remove(annotation);
     if (payloadElement.ExpandedElement != null)
     {
         this.Recurse(payloadElement.ExpandedElement);
     }
 }
        /// <summary>
        /// Normalizes an expanded link.
        /// </summary>
        /// <param name="payloadElement">The payload element to normalize.</param>
        public override void Visit(ExpandedLink payloadElement)
        {
            base.Visit(payloadElement);

            // Expanded link Url is only writtern for responses.
            if (this.testConfiguration.IsRequest)
            {
                payloadElement.UriString = null;
            }
        }
Esempio n. 8
0
        /// <summary>
        /// Visits the payload element
        /// </summary>
        /// <param name="payloadElement">The payload element to visit</param>
        public override void Visit(ExpandedLink payloadElement)
        {
            ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");
            var annotation = payloadElement.Annotations.Where(a => a is NavigationPropertyAnnotation).SingleOrDefault();

            payloadElement.Annotations.Remove(annotation);
            if (payloadElement.ExpandedElement != null)
            {
                this.Recurse(payloadElement.ExpandedElement);
            }
        }
Esempio n. 9
0
 /// <summary>
 /// Visits a payload element whose root is a ExpandedLink.
 /// </summary>
 /// <param name="payloadElement">The root node of payload element being visited.</param>
 public void Visit(ExpandedLink payloadElement)
 {
     this.isRootElement = false;
     if (payloadElement.ExpandedElement == null)
     {
         this.writer.WriteNull();
     }
     else
     {
         payloadElement.ExpandedElement.Accept(this);
     }
 }
Esempio n. 10
0
        /// <summary>
        /// Initializes a new expanded ODataNavigationLink instance and visits the payload.
        /// </summary>
        /// <param name="payloadElement">The expanded link to visit.</param>
        public override void Visit(ExpandedLink 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);

            this.writer.WriteStart(navigationLink);
            base.Visit(payloadElement);
            this.writer.WriteEnd();
        }
 /// <summary>
 /// Visits the payload element
 /// </summary>
 /// <param name="payloadElement">The payload element to visit</param>
 public override void Visit(ExpandedLink payloadElement)
 {
     ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");
     string contenttype = null;
     if (payloadElement.IsSingleEntity)
     {
         contenttype = "application/atom+xml;type=entry";
     }
     else
     {
         contenttype = "application/atom+xml;type=feed";
     }
     payloadElement.Add(new ContentTypeAnnotation(contenttype));
     if (payloadElement.ExpandedElement != null)
     {
         this.Recurse(payloadElement.ExpandedElement);
     }
 }
Esempio n. 12
0
        /// <summary>
        /// Visits the payload element
        /// </summary>
        /// <param name="payloadElement">The payload element to visit</param>
        public override void Visit(ExpandedLink payloadElement)
        {
            ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");
            string contenttype = null;

            if (payloadElement.IsSingleEntity)
            {
                contenttype = "application/atom+xml;type=entry";
            }
            else
            {
                contenttype = "application/atom+xml;type=feed";
            }
            payloadElement.Add(new ContentTypeAnnotation(contenttype));
            if (payloadElement.ExpandedElement != null)
            {
                this.Recurse(payloadElement.ExpandedElement);
            }
        }
Esempio n. 13
0
        /// <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(ExpandedLink payloadElement)
        {
            ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");
            ODataPayloadElement replacedExpandedElement = null;

            if (payloadElement.ExpandedElement != null)
            {
                replacedExpandedElement = this.Recurse(payloadElement.ExpandedElement);
            }

            if (!this.ShouldReplace(payloadElement.ExpandedElement, replacedExpandedElement))
            {
                return(payloadElement);
            }

            return(payloadElement.ReplaceWith(new ExpandedLink(replacedExpandedElement)
            {
                UriString = payloadElement.UriString
            }));
        }
Esempio n. 14
0
        /// <summary>
        /// Visits the payload element and annotates it with metadata
        /// </summary>
        /// <param name="payloadElement">The payload element to visit</param>
        public override void Visit(ExpandedLink payloadElement)
        {
            ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");
            var navigation = this.MetadataStack.Peek() as NavigationProperty;

            ExceptionUtilities.CheckObjectNotNull(navigation, "Expected navigation, got '{0}'", this.MetadataStack.Peek());
            payloadElement.AddAnnotationIfNotExist(new NavigationPropertyAnnotation()
            {
                Property = navigation
            });

            if (payloadElement.ExpandedElement != null)
            {
                try
                {
                    this.MetadataStack.Push(this.CurrentEntitySet.GetRelatedEntitySet(navigation));
                    this.Recurse(payloadElement.ExpandedElement);
                }
                finally
                {
                    this.MetadataStack.Pop();
                }
            }
        }
Esempio n. 15
0
            /// <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>
 /// Visits a payload element whose root is a ExpandedLink.
 /// </summary>
 /// <param name="payloadElement">The root node of payload element being visited.</param>
 public void Visit(ExpandedLink payloadElement)
 {
     this.isRootElement = false;
     if (payloadElement.ExpandedElement == null)
     {
         this.writer.WriteNull();
     }
     else
     {
         payloadElement.ExpandedElement.Accept(this);
     }
 }
        /// <summary>
        /// Initializes a new expanded ODataNavigationLink instance and visits the payload.
        /// </summary>
        /// <param name="payloadElement">The expanded link to visit.</param>
        public override void Visit(ExpandedLink 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);

            this.writer.WriteStart(navigationLink);
            base.Visit(payloadElement);
            this.writer.WriteEnd();
        }
        /// <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 override void Visit(ExpandedLink payloadElement)
 {
     payloadElement.UriString = null;
     base.Visit(payloadElement);
 }
 /// <summary>
 /// Visits a payload element whose root is an ExpandedLink.
 /// </summary>
 /// <param name="payloadElement">The root node of payload element being visited.</param>
 public void Visit(ExpandedLink payloadElement)
 {
     if (payloadElement.ExpandedElement != null)
     {
         this.RecurseWithMessage(payloadElement.ExpandedElement, this.expectedValueStack.Peek(), "Expanded item did not match expectation");
     }
 }
        /// <summary>
        /// Initializes a new expanded ODataNavigationLink instance and visits the payload.
        /// </summary>
        /// <param name="payloadElement">The expanded link to visit.</param>
        public override void Visit(ExpandedLink payloadElement)
        {
            Debug.Assert(this.items.Peek() is ODataNavigationLink);
            ODataNavigationLink navigationLink = (ODataNavigationLink) this.items.Pop();
           
            navigationLink.IsCollection = !payloadElement.IsSingleEntity;
            // TODO, ckerer: where do I get the info whether this links is a singleton or collection?
            if (payloadElement.UriString != null)
            {
                navigationLink.Url = new Uri(payloadElement.UriString);
            }

            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);
            base.Visit(payloadElement);
            this.currentPropertyPosition++;
        }
        /// <summary>
        /// Visits the payload element and annotates it with metadata
        /// </summary>
        /// <param name="payloadElement">The payload element to visit</param>
        public override void Visit(ExpandedLink payloadElement)
        {
            ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");
            var navigation = this.MetadataStack.Peek() as NavigationProperty;
            ExceptionUtilities.CheckObjectNotNull(navigation, "Expected navigation, got '{0}'", this.MetadataStack.Peek());
            payloadElement.AddAnnotationIfNotExist(new NavigationPropertyAnnotation() { Property = navigation });

            if (payloadElement.ExpandedElement != null)
            {
                try
                {
                    this.MetadataStack.Push(this.CurrentEntitySet.GetRelatedEntitySet(navigation));
                    this.Recurse(payloadElement.ExpandedElement);
                }
                finally
                {
                    this.MetadataStack.Pop();
                }
            }
        }
 /// <summary>
 /// Visits the payload element.
 /// </summary>
 /// <param name="payloadElement">The payload element to visit.</param>
 public override void Visit(ExpandedLink payloadElement)
 {
     payloadElement.UriString = null;
     base.Visit(payloadElement);
 }
Esempio n. 24
0
        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>
        /// 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>
        /// 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;
            }
        }