Пример #1
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(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)));
        }
Пример #2
0
            /// <summary>
            /// Visits the payload element
            /// </summary>
            /// <param name="payloadElement">The payload element to visit</param>
            public override void Visit(NavigationPropertyInstance payloadElement)
            {
                ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");

                using (this.parent.AssertHandler.WithMessage("In navigation property '{0}'", payloadElement.Name))
                {
                    var currentValue = this.queryValueStack.Peek() as QueryStructuralValue;
                    ExceptionUtilities.CheckObjectNotNull(currentValue, "The current value was not structural");

                    if (currentValue.Type.Properties.Any(p => p.Name == payloadElement.Name))
                    {
                        try
                        {
                            this.navigationStack.Push(payloadElement);
                            this.queryValueStack.Push(currentValue.GetValue(payloadElement.Name));
                            base.Visit(payloadElement);
                        }
                        finally
                        {
                            this.navigationStack.Pop();
                            this.queryValueStack.Pop();
                        }
                    }
                }
            }
Пример #3
0
        /// <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);
                }
            }
        }
Пример #4
0
        /// <summary>
        /// Generates the next link for an expanded feed.
        /// </summary>
        /// <param name="containingEntity">The containing entity.</param>
        /// <param name="navigation">The expanded navigation property.</param>
        /// <param name="lastEntityValue">The last entity value.</param>
        /// <returns>
        /// The expected next link
        /// </returns>
        public string GenerateExpandedNextLink(EntityInstance containingEntity, NavigationPropertyInstance navigation, QueryStructuralValue lastEntityValue)
        {
            ExceptionUtilities.CheckArgumentNotNull(containingEntity, "containingEntity");
            ExceptionUtilities.CheckArgumentNotNull(navigation, "navigation");
            ExceptionUtilities.CheckArgumentNotNull(lastEntityValue, "lastEntityValue");

            var navigationUriString = ((ExpandedLink)navigation.Value).UriString;

            if (string.IsNullOrEmpty(navigationUriString))
            {
                navigationUriString = UriHelpers.ConcatenateUriSegments(containingEntity.EditLink, navigation.Name);
            }

            var skipTokenValues = new List <object>();

            foreach (var keyProperty in lastEntityValue.Type.Properties.Where(p => p.IsPrimaryKey))
            {
                skipTokenValues.Add(lastEntityValue.GetScalarValue(keyProperty.Name).Value);
            }

            var skiptoken = this.BuildSkipTokenFromValues(skipTokenValues);

            var nextLinkUri = new ODataUri(new UnrecognizedSegment(navigationUriString));

            nextLinkUri.SkipToken = skiptoken;

            return(this.UriToStringConverter.ConvertToString(nextLinkUri));
        }
        /// <summary>
        /// Visits the payload element
        /// </summary>
        /// <param name="payloadElement">The payload element to visit</param>
        public override void Visit(NavigationPropertyInstance payloadElement)
        {
            ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");
            ExceptionUtilities.CheckObjectNotNull(this.currentXElement, "Current XElement is not defined");
            ExceptionUtilities.Assert(!payloadElement.Annotations.OfType <XmlRewriteElementAnnotation>().Any(), "Xml rewrite is not supported on Nav Prop instances");

            if (payloadElement.Value != null)
            {
                ExceptionUtilities.Assert(
                    payloadElement.Value.ElementType == ODataPayloadElementType.DeferredLink ||
                    payloadElement.Value.ElementType == ODataPayloadElementType.LinkCollection ||
                    payloadElement.Value.ElementType == ODataPayloadElementType.ExpandedLink,
                    "Navigation property value is invalid");

                this.VisitPayloadElement(payloadElement.Value);
            }
            else if (payloadElement.AssociationLink == null)
            {
                // special case: navigation properties with null values are represented with empty href attributes
                this.VisitPayloadElement(new DeferredLink());
            }

            if (payloadElement.AssociationLink != null)
            {
                this.VisitPayloadElement(payloadElement.AssociationLink);
            }
        }
Пример #6
0
        /// <summary>
        /// Processes a navigation property.
        /// </summary>
        /// <param name="payloadElement">The navigation property to process.</param>
        public override void Visit(NavigationPropertyInstance payloadElement)
        {
            var  contentType = payloadElement.Annotations.Where(a => a is ContentTypeAnnotation).SingleOrDefault();
            bool?collection  = null;

            if (contentType != null)
            {
                collection = contentType.StringRepresentation.Contains("feed");
            }

            var link = new ODataNestedResourceInfo()
            {
                Name         = payloadElement.Name,
                IsCollection = collection
            };

            if (payloadElement.AssociationLink != null)
            {
                link.AssociationLinkUrl = new Uri(payloadElement.AssociationLink.UriString);
            }
            try
            {
                this.items.Push(link);
                base.Visit(payloadElement);
            }
            finally
            {
                link = (ODataNestedResourceInfo)this.items.Pop();
            }
        }
            /// <summary>
            /// Visits a payload element whose root is a NavigationProperty.
            /// </summary>
            /// <param name="expected">The root node of payload element being visited.</param>
            public void Visit(NavigationPropertyInstance expected)
            {
                ExceptionUtilities.CheckArgumentNotNull(expected, "expected");
                var observed = this.GetNextObservedElement <NavigationPropertyInstance>();

                using (this.Assert.WithMessage("Navigation property '{0}' did not match expectation", expected.Name))
                {
                    this.Assert.AreEqual(expected.Name, observed.Name, "Property name did not match expectation");

                    if (expected.Value == null)
                    {
                        this.Assert.IsNull(observed.Value, "Value unexpectedly non-null");
                        this.CompareAnnotations(expected.Annotations, observed.Annotations);
                    }
                    else
                    {
                        this.Assert.IsNotNull(observed.Value, "Value unexpectedly null");
                        this.CompareAnnotations(expected.Annotations, observed.Annotations);
                        this.WrapAccept(expected.Value, observed.Value);
                    }

                    // association links
                    if (expected.AssociationLink == null)
                    {
                        this.Assert.IsNull(observed.AssociationLink, "Association link unexpectedly non-null.");
                    }
                    else
                    {
                        this.Assert.IsNotNull(observed.AssociationLink, "Association link unexpectedly null.");
                        this.WrapAccept(expected.AssociationLink, observed.AssociationLink);
                    }
                }
            }
 /// <summary>
 /// Removes ATOM link metadata annotations from a <see cref="NavigationPropertyInstance"/>.
 /// </summary>
 /// <param name="payloadElement">The navigation property instance to visit.</param>
 public override void Visit(NavigationPropertyInstance payloadElement)
 {
     if (payloadElement.AssociationLink != null)
     {
         payloadElement.AssociationLink.RemoveAnnotations(typeof(XmlTreeAnnotation));
     }
     base.Visit(payloadElement);
 }
 /// <summary>
 /// Removes ATOM link metadata annotations from a <see cref="NavigationPropertyInstance"/>.
 /// </summary>
 /// <param name="payloadElement">The navigation property instance to visit.</param>
 public override void Visit(NavigationPropertyInstance payloadElement)
 {
     if (payloadElement.AssociationLink != null)
     {
         payloadElement.AssociationLink.RemoveAnnotations(typeof(XmlTreeAnnotation));
     }
     base.Visit(payloadElement);
 }
Пример #10
0
        /// <summary>
        /// Visits the payload element
        /// </summary>
        /// <param name="payloadElement">The payload element to visit</param>
        public virtual void Visit(NavigationPropertyInstance payloadElement)
        {
            ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");

            if (payloadElement.Value != null)
            {
                this.Recurse(payloadElement.Value);
            }
        }
Пример #11
0
        /// <summary>
        /// Visits a payload element whose root is a NavigationPropertyInstance.
        /// </summary>
        /// <param name="payloadElement">The root node of the payload element being visited.</param>
        public override void Visit(NavigationPropertyInstance payloadElement)
        {
            base.Visit(payloadElement);

            if (!this.requestPayload)
            {
                this.AddVersionAnnotation(payloadElement);
            }
        }
 /// <summary>
 /// Visits a Navigation Property and appends the name on to the string builder
 /// </summary>
 /// <param name="payloadElement">Navigation Property Instance</param>
 public override void Visit(NavigationPropertyInstance payloadElement)
 {
     this.currentDepth++;
     var indentString = this.GenerateIndent();
     this.builder.AppendLine(string.Format(CultureInfo.InvariantCulture, "{0}{1}", indentString, payloadElement.Name));
     this.currentDepth++;
     base.Visit(payloadElement);
     this.currentDepth--;
     this.currentDepth--;
 }
Пример #13
0
        /// <summary>
        /// Visits the payload element
        /// </summary>
        /// <param name="payloadElement">The payload element to visit</param>
        public override void Visit(NavigationPropertyInstance payloadElement)
        {
            ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");

            if (payloadElement.Value != null)
            {
                payloadElement.Value = (payloadElement.Value.WithTitleAttribute(payloadElement.Name));
                this.Recurse(payloadElement.Value);
            }
        }
Пример #14
0
 /// <summary>
 /// Visits the payload element
 /// </summary>
 /// <param name="payloadElement">The payload element to visit</param>
 public override void Visit(NavigationPropertyInstance payloadElement)
 {
     ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");
     
     if (payloadElement.Value != null)
     {
         payloadElement.Value = (payloadElement.Value.WithTitleAttribute(payloadElement.Name));
         this.Recurse(payloadElement.Value);
     }
 }
Пример #15
0
        /// <summary>
        /// Verify that the title attribute of navigation/relationship link is not null and has the value consistent with the navigation property name.
        /// </summary>
        /// <param name="navigation">navigation property instance for the navigation link</param>
        /// <param name="link">The navigation/relationship link to verify.</param>
        /// <param name="request">The request needed for error report.</param>
        /// <param name="response">The response needed for error report.</param>
        private void VerifyAtomTitleAttribute(NavigationPropertyInstance navigation, ODataPayloadElement link, ODataRequest request, ODataResponse response)
        {
            TitleAnnotation titleAnnotation = link.Annotations.OfType <TitleAnnotation>().SingleOrDefault();

            if (titleAnnotation == null || string.Compare(titleAnnotation.Value, navigation.Name, StringComparison.CurrentCulture) != 0)
            {
                this.Logger.WriteLine(LogLevel.Verbose, CultureInfo.InvariantCulture, "Expected navigation property Title attribute '{0}', observed '{1}'", navigation.Name, titleAnnotation == null ? "null" : titleAnnotation.Value);
                this.ReportFailure(request, response);
                throw new ResponseVerificationException();
            }
        }
        /// <summary>
        /// Visits a Navigation Property and appends the name on to the string builder
        /// </summary>
        /// <param name="payloadElement">Navigation Property Instance</param>
        public override void Visit(NavigationPropertyInstance payloadElement)
        {
            this.currentDepth++;
            var indentString = this.GenerateIndent();

            this.builder.AppendLine(string.Format(CultureInfo.InvariantCulture, "{0}{1}", indentString, payloadElement.Name));
            this.currentDepth++;
            base.Visit(payloadElement);
            this.currentDepth--;
            this.currentDepth--;
        }
Пример #17
0
        /// <summary>
        /// Visits the payload element
        /// </summary>
        /// <param name="payloadElement">The payload element to visit</param>
        public override void Visit(NavigationPropertyInstance payloadElement)
        {
            ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");
            var annotation = payloadElement.Annotations.Where(a => a is NavigationPropertyAnnotation).SingleOrDefault();

            payloadElement.Annotations.Remove(annotation);

            if (payloadElement.Value != null)
            {
                this.Recurse(payloadElement.Value);
            }
        }
Пример #18
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(NavigationPropertyInstance payloadElement)
        {
            ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");
            var navigation = this.MetadataStack.Peek() as NavigationProperty;

            ExceptionUtilities.CheckObjectNotNull(navigation, "Expected navigation, got '{0}'", this.MetadataStack.Peek());
            ExceptionUtilities.Assert(payloadElement.Name == navigation.Name, "Property name mismatch");
            payloadElement.AddAnnotationIfNotExist(new NavigationPropertyAnnotation()
            {
                Property = navigation
            });
            this.Recurse(payloadElement.Value);
        }
        /// <summary>
        /// Converts the complex property into a navigation property based on if the base returned an entity instance
        /// </summary>
        /// <param name="payloadElement">The payload element to potentially replace</param>
        /// <returns>The original element or a copy to replace it with</returns>
        public override ODataPayloadElement Visit(ComplexProperty payloadElement)
        {
            ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");
            var replaced = (ComplexProperty)base.Visit(payloadElement);

            ExceptionUtilities.CheckObjectNotNull(replaced, "ComplexProperty Expected");
            if (replaced.Value.ElementType == ODataPayloadElementType.EntityInstance)
            {
                var navigation = new NavigationPropertyInstance(replaced.Name, replaced.Value);
                return(replaced.ReplaceWith(navigation));
            }

            return(replaced);
        }
        private IEnumerable <NavigationPropertyInstance> DeserializeRelationshipLinks(IEnumerable <XElement> links, List <NavigationPropertyInstance> navigationProperties)
        {
            // get the links and convert them into relationship links
            IDictionary <string, XElement> relationshipLinks = links
                                                               .Select(link => link.Attribute(Rel))
                                                               .Where(rel => rel != null)
                                                               .Where(rel => rel.Value.StartsWith(ODataConstants.DataServicesRelatedLinksNamespaceName, StringComparison.OrdinalIgnoreCase))
                                                               .ToDictionary(
                rel => rel.Value.Substring(ODataConstants.DataServicesRelatedLinksNamespaceName.Length),
                rel => rel.Parent);

            foreach (var relationshipLink in relationshipLinks)
            {
                NavigationPropertyInstance np = navigationProperties.FirstOrDefault(n => string.Compare(n.Name, relationshipLink.Key, StringComparison.Ordinal) == 0);
                XAttribute hrefAttribute      = relationshipLink.Value.Attribute(Href);

                if (np == null)
                {
                    NavigationPropertyInstance newNp = new NavigationPropertyInstance();
                    newNp.Name = relationshipLink.Key;

                    if (hrefAttribute != null)
                    {
                        newNp.AssociationLink = new DeferredLink()
                        {
                            UriString = hrefAttribute.Value
                        };
                    }

                    this.AddLinkAttributes(newNp.AssociationLink, relationshipLink.Value);
                    navigationProperties.Add(newNp);
                }
                else
                {
                    if (hrefAttribute != null)
                    {
                        np.AssociationLink = new DeferredLink()
                        {
                            UriString = hrefAttribute.Value
                        };
                    }

                    this.AddLinkAttributes(np.AssociationLink, relationshipLink.Value);
                }
            }

            return(navigationProperties);
        }
        /// <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);
        }
Пример #22
0
        /// <summary>
        /// Validator for stream properties in requests.
        /// </summary>
        /// <param name="payloadElement">The payload element to validate.</param>
        /// <param name="testConfigLimits">The test configuration limits to modify.</param>
        public static void AssociationLinkValidator(ODataPayloadElement payloadElement, TestConfigurationLimits testConfigLimits)
        {
            NavigationPropertyInstance navigationProperty = payloadElement as NavigationPropertyInstance;

            ExceptionUtilities.Assert(navigationProperty != null, "This validator only works on navigation properties.");

            if (navigationProperty.AssociationLink != null)
            {
                // Association links are not allowed in requests.
                testConfigLimits.DisallowRequest();

                // Association links can only be read if MPV >= V3, they are recognized even in <V3 payloads
                // but we don't have a way to specify this here, so just mark them as >=V3 as well.
                testConfigLimits.RaiseMinPayloadVersion(ODataVersion.V4);
            }
        }
        /// <summary>
        /// Normalizes navigation property.
        /// </summary>
        /// <param name="payloadElement">The payload element to normalize.</param>
        public override void Visit(NavigationPropertyInstance payloadElement)
        {
            base.Visit(payloadElement);

            // Each navigation property has navigation link - in JSON Light we never report just association link.
            if (payloadElement.Value == null)
            {
                payloadElement.Value = new DeferredLink();
            }

            // Each navigation property always has association link in response due to templating.
            // If it wasn't present, fill an empty one in.
            if (payloadElement.AssociationLink == null && !this.testConfiguration.IsRequest)
            {
                payloadElement.AssociationLink = new DeferredLink();
            }
        }
        /// <summary>
        /// Normalizes navigation property.
        /// </summary>
        /// <param name="payloadElement">The payload element to normalize.</param>
        public override void Visit(NavigationPropertyInstance payloadElement)
        {
            base.Visit(payloadElement);

            // Each navigation property has navigation link - in JSON Light we never report just association link.
            if (payloadElement.Value == null)
            {
                payloadElement.Value = new DeferredLink();
            }

            // Each navigation property always has association link in response due to templating.
            // If it wasn't present, fill an empty one in.
            if (payloadElement.AssociationLink == null && !this.testConfiguration.IsRequest)
            {
                payloadElement.AssociationLink = new DeferredLink();
            }
        }
        private IEnumerable <NavigationPropertyInstance> DeserializeNavigationProperties(IEnumerable <XElement> links)
        {
            // get the links and convert them into navigation properties
            ILookup <string, XElement> linksByName = links
                                                     .Select(link => link.Attribute(Rel))
                                                     .Where(rel => rel != null)
                                                     .Where(rel => rel.Value.StartsWith(ODataConstants.DataServicesRelatedNamespaceName, StringComparison.OrdinalIgnoreCase))
                                                     .ToLookup(
                rel => rel.Value.Substring(ODataConstants.DataServicesRelatedNamespaceName.Length),
                rel => rel.Parent);

            List <NavigationPropertyInstance> results = new List <NavigationPropertyInstance>(linksByName.Count);

            foreach (var group in linksByName)
            {
                NavigationPropertyInstance navProp = new NavigationPropertyInstance();
                navProp.Name = group.Key;
                List <XElement> elements = group.ToList();

                if (elements.Count > 1)
                {
                    LinkCollection collection = new LinkCollection();
                    foreach (XElement link in elements)
                    {
                        ODataPayloadElement linkValue = this.DeserializeLink(link);
                        ExceptionUtilities.Assert(
                            linkValue.ElementType == ODataPayloadElementType.DeferredLink,
                            "Navigation property '" + group.Key + "' had multiple <link> elements which were not all deferred");

                        collection.Add(linkValue);
                    }

                    navProp.Value = collection;
                }
                else
                {
                    // Note: it is possible in cases where we are parsing an update payload, that this was really a collection of size one
                    // however, we cannot possibly detect this case here, so we will have to deal with it elsewhere should it arise
                    navProp.Value = this.DeserializeLink(elements[0]);
                }

                results.Add(navProp);
            }

            return(results);
        }
Пример #26
0
        /// <summary>
        /// Verify the navigation link is as expected.
        /// </summary>
        /// <param name="navigation">navigation link to verify</param>
        /// <param name="expectedNavigationUri">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 VerifyNavigationLink(NavigationPropertyInstance navigation, string expectedNavigationUri, ODataRequest request, ODataResponse response)
        {
            if (navigation.IsExpanded)
            {
                this.VerifyLinkUriValue(((ExpandedLink)navigation.Value).UriString, expectedNavigationUri, request, response);
            }
            else
            {
                this.VerifyLinkUriValue(((DeferredLink)navigation.Value).UriString, expectedNavigationUri, request, response);
            }

            // extra verifications for atom payload
            if (this.IsAtomResponse(response))
            {
                this.VerifyAtomNavigationLinkTypeAttribute(navigation.Value, request, response);
                this.VerifyAtomTitleAttribute(navigation, navigation.Value, request, response);
            }
        }
Пример #27
0
            /// <summary>
            /// Visits a payload element whose root is a NavigationProperty.
            /// </summary>
            /// <param name="payloadElement">The root node of payload element being visited.</param>
            public void Visit(NavigationPropertyInstance payloadElement)
            {
                this.isRootElement = false;
                ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");
                if (payloadElement.Name != null)
                {
                    this.writer.WriteName(payloadElement.Name);
                }

                if (payloadElement.Value == null)
                {
                    this.writer.WriteNull();
                }
                else
                {
                    this.Recurse(payloadElement.Value);
                }
            }
Пример #28
0
        /// <summary>
        /// Verify the expanded navigation link is as expected.
        /// </summary>
        /// <param name="navigation">expanded navigation link to verify</param>
        /// <param name="expectedNavigationUri">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 VerifyNavigationExpandedLink(NavigationPropertyInstance navigation, string expectedNavigationUri, ODataRequest request, ODataResponse response)
        {
            if (this.IsAtomResponse(response))
            {
                this.VerifyNavigationLink(navigation, expectedNavigationUri, request, response);
            }
            else
            {
                // JSON never has navigation links for expanded elements
                string expandedLinkUri = ((ExpandedLink)navigation.Value).UriString;
                if (expandedLinkUri != null)
                {
                    this.Logger.WriteLine(LogLevel.Verbose, CultureInfo.InvariantCulture, "Expected expanded link uri == null, observed {0}", expandedLinkUri);
                    this.ReportFailure(request, response);
                    throw new ResponseVerificationException();
                }
            }

            List <EntityInstance> expandedEntities = new List <EntityInstance>();
            ODataPayloadElement   expandedElement  = ((ExpandedLink)navigation.Value).ExpandedElement;

            if (expandedElement != null)
            {
                EntityInstance entityInstance = expandedElement as EntityInstance;
                if (entityInstance != null)
                {
                    expandedEntities.Add(entityInstance);
                }
                else
                {
                    EntitySetInstance entitySetInstance = expandedElement as EntitySetInstance;

                    foreach (EntityInstance ei in entitySetInstance)
                    {
                        expandedEntities.Add(ei);
                    }
                }

                this.VerifyEntityLinks(request, response, expandedEntities);
            }
        }
Пример #29
0
        /// <summary>
        /// Generates all interesting reader payloads for the given <paramref name="navPropertyPayload"/>.
        /// </summary>
        /// <param name="navPropertyPayload">The navigation property payload to use in the generated payloads.</param>
        /// <returns>All interesting reader payloads for the given <paramref name="navPropertyPayload"/>.</returns>
        /// <remarks>
        /// This method assumes that the <paramref name="navPropertyPayload"/> represents a deferred navigation property. It will
        /// return the navigation property as deferred link first and will then expand it to singleton and collection
        /// expanded navigation properties.
        /// </remarks>
        private IEnumerable <T> GenerateNavigationPropertyPayloads <T>(T navPropertyPayload) where T : PayloadTestDescriptor
        {
            this.Assert.IsNotNull(navPropertyPayload, "navPropertyPayload != null");
            this.Assert.IsNotNull(navPropertyPayload.PayloadElement, "navPropertyPayload.PayloadElement != null");

            NavigationPropertyInstance navPropertyInstance = navPropertyPayload.PayloadElement as NavigationPropertyInstance;

            this.Assert.IsNotNull(navPropertyInstance, "navPropertyInstance != null");
            this.Assert.IsTrue(navPropertyInstance.Value is DeferredLink, "Expected a deferred link navigation property.");

            // return the navigation property as as part of an entry with deferred link
            yield return(navPropertyPayload.InEntity());

            // return the navigation property as as part of an entry with deferred link
            yield return(navPropertyPayload.InEntity(2, 2));

            // return the navigation property as part of an entry with an expanded (singleton) link
            yield return(navPropertyPayload.ExpandNavigationProperty(true).InEntity());

            // return the navigation property as part of an entry with an expanded (singleton) link
            yield return(navPropertyPayload.ExpandNavigationProperty(true).InEntity(2, 2));

            // return the navigation property as part of an entry (incl. nav props) with an expanded (singleton) link
            yield return(navPropertyPayload.ExpandNavigationProperty(true).InEntity(15, 15));

            // return the navigation property as part of an entry with an expanded (multi) link (with a single entry)
            yield return(navPropertyPayload.ExpandNavigationProperty(false, 1).InEntity());

            // return the navigation property as part of an entry with an expanded (multi) link (with multiple entries)
            yield return(navPropertyPayload.ExpandNavigationProperty(false, 3).InEntity());

            // return the navigation property as part of an entry with an expanded (multi) link
            yield return(navPropertyPayload.ExpandNavigationProperty(false, 3).InEntity(2, 2));

            // return the navigation property as part of an entry (incl. nav props) with an expanded (multi) link
            yield return(navPropertyPayload.ExpandNavigationProperty(false, 3).InEntity(15, 15));

            // return the navigation property as part of an entry with an expanded (multi) link with next link
            yield return(navPropertyPayload.ExpandNavigationProperty(false, 3, "http://odata.org/nextlink").InEntity(2, 2));
        }
            /// <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);
            }
Пример #31
0
        /// <summary>
        /// Builds a complex instance from the given payloadElements to represent a parameters payload.
        /// </summary>
        /// <param name="payloadElements">Each ODataPayloadElement represents the value for each parameter.</param>
        /// <param name="model">EdmModel instance.</param>
        /// <param name="functionImportName">Name of the function import to add to the model.</param>
        /// <returns></returns>
        private static ComplexInstance PayloadElementsToParameterPayload(ODataPayloadElement[] payloadElements, EdmModel model, string functionImportName)
        {
            EdmOperationImport operationImport = (EdmOperationImport)model.EntityContainer.FindOperationImports(functionImportName).FirstOrDefault();
            EdmOperation       operation       = (EdmOperation)operationImport.Operation;

            var parameterPayload = new ComplexInstance(null, false);

            for (int idx = 0; idx < payloadElements.Length; idx++)
            {
                ODataPayloadElement p           = payloadElements[idx];
                string            parameterName = "p" + idx;
                PropertyInstance  parameter;
                IEdmTypeReference entityModelType = p.GetAnnotation <EntityModelTypeAnnotation>().EdmModelType;
                switch (p.ElementType)
                {
                case ODataPayloadElementType.PrimitiveValue:
                    object         clrValue       = ((PrimitiveValue)p).ClrValue;
                    PrimitiveValue primitiveValue = new PrimitiveValue(clrValue == null ? null : clrValue.GetType().FullName, clrValue);
                    primitiveValue.CopyAnnotation <PrimitiveValue, EntityModelTypeAnnotation>(p);
                    parameter = new PrimitiveProperty(parameterName, primitiveValue);
                    operation.AddParameter(parameterName, MetadataUtils.GetPrimitiveTypeReference(primitiveValue.ClrValue.GetType()));
                    break;

                case ODataPayloadElementType.ComplexInstance:
                    parameter = new ComplexProperty(parameterName, (ComplexInstance)p);
                    operation.AddParameter(parameterName, entityModelType);
                    break;

                case ODataPayloadElementType.PrimitiveMultiValue:
                    PrimitiveMultiValue primitiveMultiValue = (PrimitiveMultiValue)p;
                    if (primitiveMultiValue.Annotations.OfType <JsonCollectionResultWrapperAnnotation>().SingleOrDefault() == null)
                    {
                        primitiveMultiValue.Annotations.Add(new JsonCollectionResultWrapperAnnotation(false));
                    }

                    parameter = new PrimitiveMultiValueProperty(parameterName, primitiveMultiValue);
                    operation.AddParameter(parameterName, entityModelType);
                    break;

                case ODataPayloadElementType.ComplexMultiValue:
                    ComplexMultiValue complexMultiValue = (ComplexMultiValue)p;
                    if (complexMultiValue.Annotations.OfType <JsonCollectionResultWrapperAnnotation>().SingleOrDefault() == null)
                    {
                        complexMultiValue.Annotations.Add(new JsonCollectionResultWrapperAnnotation(false));
                    }

                    parameter = new ComplexMultiValueProperty(parameterName, complexMultiValue);
                    operation.AddParameter(parameterName, entityModelType);
                    break;

                case ODataPayloadElementType.EntityInstance:
                    parameter = new NavigationPropertyInstance(parameterName, (EntityInstance)p);
                    operation.AddParameter(parameterName, entityModelType);
                    break;

                case ODataPayloadElementType.EntitySetInstance:
                    parameter = new NavigationPropertyInstance(parameterName, (EntitySetInstance)p);
                    operation.AddParameter(parameterName, entityModelType);
                    break;

                default:
                    throw new NotSupportedException("PayloadElementsToParameterPayload() is called on unsupported ODataPayloadElement type: " + p.ElementType);
                }

                parameterPayload.Add(parameter);
            }

            parameterPayload.ExpectedFunctionImport(operationImport);
            return(parameterPayload);
        }
        /// <summary>
        /// Visits a payload element whose root is a NavigationPropertyInstance.
        /// </summary>
        /// <param name="payloadElement">The root node of the payload element being visited.</param>
        public override void Visit(NavigationPropertyInstance payloadElement)
        {
            base.Visit(payloadElement);

            if (!this.requestPayload)
            {
                this.AddVersionAnnotation(payloadElement);
            }
        }
Пример #33
0
        /// <summary>
        /// Builds a complex instance from the given payloadElements to represent a parameters payload.
        /// </summary>
        /// <param name="payloadElements">Each ODataPayloadElement represents the value for each parameter.</param>
        /// <param name="model">EdmModel instance.</param>
        /// <param name="functionImportName">Name of the function import to add to the model.</param>
        /// <returns></returns>
        private static ComplexInstance PayloadElementsToParameterPayload(ODataPayloadElement[] payloadElements, EdmModel model, string functionImportName)
        {
            EdmOperationImport operationImport = (EdmOperationImport)model.EntityContainer.FindOperationImports(functionImportName).FirstOrDefault();
            EdmOperation operation = (EdmOperation)operationImport.Operation;
            
            var parameterPayload = new ComplexInstance(null, false);
            for (int idx = 0; idx < payloadElements.Length; idx++)
            {
                ODataPayloadElement p = payloadElements[idx];
                string parameterName = "p" + idx;
                PropertyInstance parameter;
                IEdmTypeReference entityModelType = p.GetAnnotation<EntityModelTypeAnnotation>().EdmModelType;
                switch (p.ElementType)
                {
                    case ODataPayloadElementType.PrimitiveValue:
                        object clrValue = ((PrimitiveValue)p).ClrValue;
                        PrimitiveValue primitiveValue = new PrimitiveValue(clrValue == null ? null : clrValue.GetType().FullName, clrValue);
                        primitiveValue.CopyAnnotation<PrimitiveValue, EntityModelTypeAnnotation>(p);
                        parameter = new PrimitiveProperty(parameterName, primitiveValue);
                        operation.AddParameter(parameterName, MetadataUtils.GetPrimitiveTypeReference(primitiveValue.ClrValue.GetType()));
                        break;

                    case ODataPayloadElementType.ComplexInstance:
                        parameter = new ComplexProperty(parameterName, (ComplexInstance)p);
                        operation.AddParameter(parameterName, entityModelType);
                        break;

                    case ODataPayloadElementType.PrimitiveMultiValue:
                        PrimitiveMultiValue primitiveMultiValue = (PrimitiveMultiValue)p;
                        if (primitiveMultiValue.Annotations.OfType<JsonCollectionResultWrapperAnnotation>().SingleOrDefault() == null)
                        {
                            primitiveMultiValue.Annotations.Add(new JsonCollectionResultWrapperAnnotation(false));
                        }

                        parameter = new PrimitiveMultiValueProperty(parameterName, primitiveMultiValue);
                        operation.AddParameter(parameterName, entityModelType);
                        break;

                    case ODataPayloadElementType.ComplexMultiValue:
                        ComplexMultiValue complexMultiValue = (ComplexMultiValue)p;
                        if (complexMultiValue.Annotations.OfType<JsonCollectionResultWrapperAnnotation>().SingleOrDefault() == null)
                        {
                            complexMultiValue.Annotations.Add(new JsonCollectionResultWrapperAnnotation(false));
                        }

                        parameter = new ComplexMultiValueProperty(parameterName, complexMultiValue);
                        operation.AddParameter(parameterName, entityModelType);
                        break;

                    case ODataPayloadElementType.EntityInstance:
                        parameter = new NavigationPropertyInstance(parameterName, (EntityInstance)p);
                        operation.AddParameter(parameterName, entityModelType);
                        break;

                    case ODataPayloadElementType.EntitySetInstance:
                        parameter = new NavigationPropertyInstance(parameterName, (EntitySetInstance)p);
                        operation.AddParameter(parameterName, entityModelType);
                        break;

                    default:
                        throw new NotSupportedException("PayloadElementsToParameterPayload() is called on unsupported ODataPayloadElement type: " + p.ElementType);
                }

                parameterPayload.Add(parameter);
            }

            parameterPayload.ExpectedFunctionImport(operationImport);
            return parameterPayload;
        }
Пример #34
0
        /// <summary>
        /// Visits an entity instance: creates a new ODataEntry instance, collects and sets all the properties,
        /// calls ODataWriter.WriteStart(), then visits the navigation properties and calls ODataWriter.WriteEnd()
        /// </summary>
        /// <param name="payloadElement">The entity instance to write.</param>
        public override void Visit(EntityInstance payloadElement)
        {
            // create an ODataEntry and write it
            string editLinkString = payloadElement.GetEditLink();
            string selfLinkString = payloadElement.GetSelfLink();
            string entryId        = payloadElement.Id;

            var entry = new ODataEntry()
            {
                Id                = string.IsNullOrEmpty(entryId) ? null:new Uri(entryId),
                ETag              = payloadElement.ETag,
                EditLink          = string.IsNullOrEmpty(editLinkString) ? null : new Uri(editLinkString),
                ReadLink          = string.IsNullOrEmpty(selfLinkString) ? null : new Uri(selfLinkString),
                TypeName          = payloadElement.FullTypeName,
                SerializationInfo = new ODataFeedAndEntrySerializationInfo()
                {
                    NavigationSourceEntityTypeName = payloadElement.FullTypeName,
                    NavigationSourceName           = "MySet",
                    ExpectedTypeName = payloadElement.FullTypeName
                }
            };

            if (payloadElement.IsMediaLinkEntry())
            {
                ODataStreamReferenceValue mediaResource = new ODataStreamReferenceValue();
                mediaResource.ContentType = payloadElement.StreamContentType;
                mediaResource.ETag        = payloadElement.StreamETag;

                mediaResource.ReadLink = new Uri(payloadElement.StreamSourceLink);
                mediaResource.EditLink = new Uri(payloadElement.StreamEditLink);

                entry.MediaResource = mediaResource;
            }

            // TODO: add support for custom extensions at some point
            AddEntryMetadata(payloadElement, entry);

            Debug.Assert(this.currentNavigationProperties.Count == 0);
            Debug.Assert(this.currentProperties.Count == 0);

            // visit the properties (incl. navigation properties and named stream properties)
            base.Visit(payloadElement);

            // set the primitive and complex properties
            if (this.currentProperties.Count > 0)
            {
                entry.Properties       = this.currentProperties;
                this.currentProperties = new List <ODataProperty>();
            }

            this.writer.WriteStart(entry);

            var navigationProperties = new ReadOnlyCollection <NavigationPropertyInstance>(this.currentNavigationProperties);

            this.currentNavigationProperties.Clear();

            // process the navigation properties/links
            for (int i = 0; i < navigationProperties.Count; ++i)
            {
                NavigationPropertyInstance navigationProperty = navigationProperties[i];
                this.currentLink = new ODataNavigationLink()
                {
                    Name = navigationProperty.Name
                };
                base.Visit(navigationProperty);
                Debug.Assert(this.currentLink == null);
            }

            this.writer.WriteEnd();
        }
        private IEnumerable<NavigationPropertyInstance> DeserializeNavigationProperties(IEnumerable<XElement> links)
        {
            // get the links and convert them into navigation properties
            ILookup<string, XElement> linksByName = links
                .Select(link => link.Attribute(Rel))
                .Where(rel => rel != null)
                .Where(rel => rel.Value.StartsWith(ODataConstants.DataServicesRelatedNamespaceName, StringComparison.OrdinalIgnoreCase))
                .ToLookup(
                    rel => rel.Value.Substring(ODataConstants.DataServicesRelatedNamespaceName.Length),
                    rel => rel.Parent);

            List<NavigationPropertyInstance> results = new List<NavigationPropertyInstance>(linksByName.Count);
            foreach (var group in linksByName)
            {
                NavigationPropertyInstance navProp = new NavigationPropertyInstance();
                navProp.Name = group.Key;
                List<XElement> elements = group.ToList();

                if (elements.Count > 1)
                {
                    LinkCollection collection = new LinkCollection();
                    foreach (XElement link in elements)
                    {
                        ODataPayloadElement linkValue = this.DeserializeLink(link);
                        ExceptionUtilities.Assert(
                            linkValue.ElementType == ODataPayloadElementType.DeferredLink,
                            "Navigation property '" + group.Key + "' had multiple <link> elements which were not all deferred");

                        collection.Add(linkValue);
                    }

                    navProp.Value = collection;
                }
                else
                {
                    // Note: it is possible in cases where we are parsing an update payload, that this was really a collection of size one
                    // however, we cannot possibly detect this case here, so we will have to deal with it elsewhere should it arise
                    navProp.Value = this.DeserializeLink(elements[0]);
                }

                results.Add(navProp);
            }

            return results;
        }
        /// <summary>
        /// Verify the navigation link is as expected.
        /// </summary>
        /// <param name="navigation">navigation link to verify</param>
        /// <param name="expectedNavigationUri">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 VerifyNavigationLink(NavigationPropertyInstance navigation, string expectedNavigationUri, ODataRequest request, ODataResponse response)
        {
            if (navigation.IsExpanded)
            {
                this.VerifyLinkUriValue(((ExpandedLink)navigation.Value).UriString, expectedNavigationUri, request, response);               
            }
            else
            {
                this.VerifyLinkUriValue(((DeferredLink)navigation.Value).UriString, expectedNavigationUri, request, response);
            }

            // extra verifications for atom payload
            if (this.IsAtomResponse(response))
            {
                this.VerifyAtomNavigationLinkTypeAttribute(navigation.Value, request, response);
                this.VerifyAtomTitleAttribute(navigation, navigation.Value, request, response);
            }
        }
 /// <summary>
 /// Verify that the title attribute of navigation/relationship link is not null and has the value consistent with the navigation property name.
 /// </summary>
 /// <param name="navigation">navigation property instance for the navigation link</param>
 /// <param name="link">The navigation/relationship link to verify.</param>
 /// <param name="request">The request needed for error report.</param>
 /// <param name="response">The response needed for error report.</param>
 private void VerifyAtomTitleAttribute(NavigationPropertyInstance navigation, ODataPayloadElement link, ODataRequest request, ODataResponse response)
 {
     TitleAnnotation titleAnnotation = link.Annotations.OfType<TitleAnnotation>().SingleOrDefault();
     if (titleAnnotation == null || string.Compare(titleAnnotation.Value, navigation.Name, StringComparison.CurrentCulture) != 0)
     {
         this.Logger.WriteLine(LogLevel.Verbose, CultureInfo.InvariantCulture, "Expected navigation property Title attribute '{0}', observed '{1}'", navigation.Name, titleAnnotation == null ? "null" : titleAnnotation.Value);
         this.ReportFailure(request, response);
         throw new ResponseVerificationException();
     }
 }
 /// <summary>
 /// Construct expected relationship link value.
 /// </summary>
 /// <param name="entity">entity that the link belongs to</param>
 /// <param name="navigation">navigation property instance for the relationship link</param>
 /// <returns>expected relationship link value</returns>
 private string BuildExpectedAssociationUri(EntityInstance entity, NavigationPropertyInstance navigation)
 {
     return UriHelpers.ConcatenateUriSegments(entity.GetEditLink(), Endpoints.Ref, Uri.EscapeDataString(navigation.Name));
 }
            /// <summary>
            /// Visits the payload element
            /// </summary>
            /// <param name="payloadElement">The payload element to visit</param>
            public override void Visit(NavigationPropertyInstance payloadElement)
            {
                ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");

                using (this.parent.AssertHandler.WithMessage("In navigation property '{0}'", payloadElement.Name))
                {
                    var currentValue = this.queryValueStack.Peek() as QueryStructuralValue;
                    ExceptionUtilities.CheckObjectNotNull(currentValue, "The current value was not structural");

                    if (currentValue.Type.Properties.Any(p => p.Name == payloadElement.Name))
                    {
                        try
                        {
                            this.navigationStack.Push(payloadElement);
                            this.queryValueStack.Push(currentValue.GetValue(payloadElement.Name));
                            base.Visit(payloadElement);
                        }
                        finally
                        {
                            this.navigationStack.Pop();
                            this.queryValueStack.Pop();
                        }
                    }
                }
            }
Пример #40
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>
 /// Visits a payload element whose root is a NavigationProperty.
 /// </summary>
 /// <param name="payloadElement">The root node of payload element being visited.</param>
 public void Visit(NavigationPropertyInstance payloadElement)
 {
     // the type in the method signature is fully qualified due to a collision with the EntityModel namespace
     this.RecurseWithMessage(payloadElement.Value, this.expectedValueStack.Peek(), "Navigation property '{0}' did not match expectation", payloadElement.Name);
 }
        private IEnumerable<NavigationPropertyInstance> DeserializeRelationshipLinks(IEnumerable<XElement> links, List<NavigationPropertyInstance> navigationProperties)
        {
            // get the links and convert them into relationship links
            IDictionary<string, XElement> relationshipLinks = links
                .Select(link => link.Attribute(Rel))
                .Where(rel => rel != null)
                .Where(rel => rel.Value.StartsWith(ODataConstants.DataServicesRelatedLinksNamespaceName, StringComparison.OrdinalIgnoreCase))
                .ToDictionary(
                    rel => rel.Value.Substring(ODataConstants.DataServicesRelatedLinksNamespaceName.Length),
                    rel => rel.Parent);

            foreach (var relationshipLink in relationshipLinks)
            {
                NavigationPropertyInstance np = navigationProperties.FirstOrDefault(n => string.Compare(n.Name, relationshipLink.Key, StringComparison.Ordinal) == 0);
                XAttribute hrefAttribute = relationshipLink.Value.Attribute(Href);

                if (np == null)
                {
                    NavigationPropertyInstance newNp = new NavigationPropertyInstance();
                    newNp.Name = relationshipLink.Key;

                    if (hrefAttribute != null)
                    {
                        newNp.AssociationLink = new DeferredLink() { UriString = hrefAttribute.Value };
                    }

                    this.AddLinkAttributes(newNp.AssociationLink, relationshipLink.Value);
                    navigationProperties.Add(newNp);
                }
                else
                {
                    if (hrefAttribute != null)
                    {
                        np.AssociationLink = new DeferredLink() { UriString = hrefAttribute.Value };
                    }

                    this.AddLinkAttributes(np.AssociationLink, relationshipLink.Value);
                }
            }

            return navigationProperties;
        }
Пример #43
0
 /// <summary>
 /// Visits the payload element
 /// </summary>
 /// <param name="payloadElement">The payload element to visit</param>
 public override void Visit(NavigationPropertyInstance payloadElement)
 {
     ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");
     var annotation = payloadElement.Annotations.Where(a => a is NavigationPropertyAnnotation).SingleOrDefault();
     payloadElement.Annotations.Remove(annotation);
     
     if (payloadElement.Value != null)
     {
         this.Recurse(payloadElement.Value);
     }
 }
 /// <summary>
 /// Processes a navigation property.
 /// </summary>
 /// <param name="payloadElement">The navigation property to process.</param>
 public override void Visit(NavigationPropertyInstance payloadElement)
 {
     this.currentNavigationProperties.Add(payloadElement);
 }
        /// <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);
                }
            }
        }
 /// <summary>
 /// Visits the payload element and annotates it with metadata
 /// </summary>
 /// <param name="payloadElement">The payload element to visit</param>
 public override void Visit(NavigationPropertyInstance payloadElement)
 {
     ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");
     var navigation = this.MetadataStack.Peek() as NavigationProperty;
     ExceptionUtilities.CheckObjectNotNull(navigation, "Expected navigation, got '{0}'", this.MetadataStack.Peek());
     ExceptionUtilities.Assert(payloadElement.Name == navigation.Name, "Property name mismatch");
     payloadElement.AddAnnotationIfNotExist(new NavigationPropertyAnnotation() { Property = navigation });
     this.Recurse(payloadElement.Value);
 }
        /// <summary>
        /// Verify the expanded navigation link is as expected.
        /// </summary>
        /// <param name="navigation">expanded navigation link to verify</param>
        /// <param name="expectedNavigationUri">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 VerifyNavigationExpandedLink(NavigationPropertyInstance navigation, string expectedNavigationUri, ODataRequest request, ODataResponse response)
        {
            if (this.IsAtomResponse(response))
            {
                this.VerifyNavigationLink(navigation, expectedNavigationUri, request, response);
            }
            else
            {
                // JSON never has navigation links for expanded elements
                string expandedLinkUri = ((ExpandedLink)navigation.Value).UriString;
                if (expandedLinkUri != null)
                {
                    this.Logger.WriteLine(LogLevel.Verbose, CultureInfo.InvariantCulture, "Expected expanded link uri == null, observed {0}", expandedLinkUri);
                    this.ReportFailure(request, response);
                    throw new ResponseVerificationException();
                }
            }

            List<EntityInstance> expandedEntities = new List<EntityInstance>();
            ODataPayloadElement expandedElement = ((ExpandedLink)navigation.Value).ExpandedElement;
            if (expandedElement != null)
            {
                EntityInstance entityInstance = expandedElement as EntityInstance;
                if (entityInstance != null)
                {
                    expandedEntities.Add(entityInstance);
                }
                else
                {
                    EntitySetInstance entitySetInstance = expandedElement as EntitySetInstance;

                    foreach (EntityInstance ei in entitySetInstance)
                    {
                        expandedEntities.Add(ei);
                    }
                }

                this.VerifyEntityLinks(request, response, expandedEntities);
            }
        }
        /// <summary>
        /// Converts the complex property into a navigation property based on if the base returned an entity instance
        /// </summary>
        /// <param name="payloadElement">The payload element to potentially replace</param>
        /// <returns>The original element or a copy to replace it with</returns>
        public override ODataPayloadElement Visit(ComplexProperty payloadElement)
        {
            ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");
            var replaced = (ComplexProperty)base.Visit(payloadElement);
            ExceptionUtilities.CheckObjectNotNull(replaced, "ComplexProperty Expected");
            if (replaced.Value.ElementType == ODataPayloadElementType.EntityInstance)
            {
                var navigation = new NavigationPropertyInstance(replaced.Name, replaced.Value);
                return replaced.ReplaceWith(navigation);
            }

            return replaced;
        }
            /// <summary>
            /// Visits a payload element whose root is a NavigationProperty.
            /// </summary>
            /// <param name="payloadElement">The root node of payload element being visited.</param>
            public void Visit(NavigationPropertyInstance payloadElement)
            {
                this.isRootElement = false;
                ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");
                if (payloadElement.Name != null)
                {                    
                    this.writer.WriteName(payloadElement.Name);
                }

                if (payloadElement.Value == null)
                {
                    this.writer.WriteNull();
                }
                else
                {
                    this.Recurse(payloadElement.Value);
                }
            }
Пример #50
0
 /// <summary>
 /// Processes a navigation property.
 /// </summary>
 /// <param name="payloadElement">The navigation property to process.</param>
 public override void Visit(NavigationPropertyInstance payloadElement)
 {
     this.currentNavigationProperties.Add(payloadElement);
 }
        /// <summary>
        /// Generates the next link for an expanded feed.
        /// </summary>
        /// <param name="containingEntity">The containing entity.</param>
        /// <param name="navigation">The expanded navigation property.</param>
        /// <param name="lastEntityValue">The last entity value.</param>
        /// <returns>
        /// The expected next link
        /// </returns>
        public string GenerateExpandedNextLink(EntityInstance containingEntity, NavigationPropertyInstance navigation, QueryStructuralValue lastEntityValue)
        {
            ExceptionUtilities.CheckArgumentNotNull(containingEntity, "containingEntity");
            ExceptionUtilities.CheckArgumentNotNull(navigation, "navigation");
            ExceptionUtilities.CheckArgumentNotNull(lastEntityValue, "lastEntityValue");

            var navigationUriString = ((ExpandedLink)navigation.Value).UriString;
            if (string.IsNullOrEmpty(navigationUriString))
            {
                navigationUriString = UriHelpers.ConcatenateUriSegments(containingEntity.EditLink, navigation.Name);
            }

            var skipTokenValues = new List<object>();
            foreach (var keyProperty in lastEntityValue.Type.Properties.Where(p => p.IsPrimaryKey))
            {
                skipTokenValues.Add(lastEntityValue.GetScalarValue(keyProperty.Name).Value);
            }

            var skiptoken = this.BuildSkipTokenFromValues(skipTokenValues);

            var nextLinkUri = new ODataUri(new UnrecognizedSegment(navigationUriString));
            nextLinkUri.SkipToken = skiptoken;

            return this.UriToStringConverter.ConvertToString(nextLinkUri);
        }
        /// <summary>
        /// Processes a navigation property.
        /// </summary>
        /// <param name="payloadElement">The navigation property to process.</param>
        public override void Visit(NavigationPropertyInstance payloadElement)
        {
            var contentType = payloadElement.Annotations.Where(a => a is ContentTypeAnnotation).SingleOrDefault();
            bool? collection = null;
            if (contentType != null)
            {
                collection = contentType.StringRepresentation.Contains("feed");
            }

            var link = new ODataNavigationLink()
            {
                Name = payloadElement.Name,
                IsCollection = collection
            };

            if (payloadElement.AssociationLink != null)
            {
                link.AssociationLinkUrl = new Uri(payloadElement.AssociationLink.UriString);
            }
            try
            {
                this.items.Push(link);
                base.Visit(payloadElement);
            }
            finally
            {
                link = (ODataNavigationLink) this.items.Pop();
            }
        }