Пример #1
0
 protected override void EndNavigationLinkWithContent(ODataNavigationLink navigationLink)
 {
     if (!this.jsonOutputContext.WritingResponse && navigationLink.IsCollection.Value)
     {
         this.jsonOutputContext.JsonWriter.EndArrayScope();
     }
 }
Пример #2
0
 internal static string ComputeODataNavigationLinkType(ODataNavigationLink navigationLink)
 {
     if (!navigationLink.IsCollection.Value)
     {
         return "application/atom+xml;type=entry";
     }
     return "application/atom+xml;type=feed";
 }
Пример #3
0
 public void AddNavigationLink(ODataNavigationLink link)
 {
     this.EntityDescriptor.AddNavigationLink(link.Name, link.Url);
     if (this.navigationLinks == null)
     {
         this.navigationLinks = new List<ODataNavigationLink>();
     }
     this.navigationLinks.Add(link);
 }
Пример #4
0
        /// <summary>Checks that for duplicate association links and if there already is a navigation link with the same name
        /// sets the association link URL on that navigation link.</summary>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker for the current scope.</param>
        /// <param name="associationLink">The association link to be checked.</param>
        internal static void CheckForDuplicateAssociationLinkAndUpdateNavigationLink(
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            ODataAssociationLink associationLink)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null");
            Debug.Assert(associationLink != null, "associationLink != null");

            ODataNavigationLink navigationLink = duplicatePropertyNamesChecker.CheckForDuplicateAssociationLinkNames(associationLink);

            // We must not set the AssociationLinkUrl to null since that would disable templating on it, but we want templating to work if the association link was not in the payload.
            if (navigationLink != null && navigationLink.AssociationLinkUrl == null && associationLink.Url != null)
            {
                navigationLink.AssociationLinkUrl = associationLink.Url;
            }
        }
        /// <summary>
        /// Checks the <paramref name="navigationLink"/> for duplicate property names in an entry when the navigation link
        /// has started but we don't know yet if it's expanded or not.
        /// </summary>
        /// <param name="navigationLink">The navigation link to be checked.</param>
        internal void CheckForDuplicatePropertyNamesOnNavigationLinkStart(ODataNavigationLink navigationLink)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(navigationLink != null, "navigationLink != null");
#if DEBUG
            this.startNavigationLinkName = navigationLink.Name;
#endif

            // Just check for duplication without modifying anything in the caches - this is to allow callers to choose whether they want to call this method first
            // or just call the CheckForDuplicatePropertyNames(ODataNavigationLink) directly.
            string            propertyName = navigationLink.Name;
            DuplicationRecord existingDuplicationRecord;
            if (this.propertyNameCache != null && this.propertyNameCache.TryGetValue(propertyName, out existingDuplicationRecord))
            {
                this.CheckNavigationLinkDuplicateNameForExistingDuplicationRecord(propertyName, existingDuplicationRecord);
            }
        }
Пример #6
0
        private void EnterScope(WriterState newState, ODataItem item)
        {
            this.InterceptException(() => this.ValidateTransition(newState));
            bool  skipWriting  = this.SkipWriting;
            Scope currentScope = this.CurrentScope;

            if (((currentScope.State == WriterState.Entry) && (newState == WriterState.NavigationLink)) && !skipWriting)
            {
                ProjectedPropertiesAnnotation projectedProperties = currentScope.Item.GetAnnotation <ProjectedPropertiesAnnotation>();
                ODataNavigationLink           link = (ODataNavigationLink)item;
                skipWriting = projectedProperties.ShouldSkipProperty(link.Name);
            }
            else if ((currentScope.State == WriterState.Feed) && (newState == WriterState.Entry))
            {
                FeedScope scope1 = (FeedScope)currentScope;
                scope1.EntryCount++;
            }
            this.PushScope(newState, item, skipWriting);
        }
Пример #7
0
        internal static IEdmType ValidateNavigationLink(ODataNavigationLink navigationLink, IEdmEntityType declaringEntityType, ODataPayloadKind?expandedPayloadKind)
        {
            if (string.IsNullOrEmpty(navigationLink.Name))
            {
                throw new ODataException(Microsoft.Data.OData.Strings.ValidationUtils_LinkMustSpecifyName);
            }
            bool flag  = ((ODataPayloadKind)expandedPayloadKind) == ODataPayloadKind.EntityReferenceLink;
            bool flag2 = ((ODataPayloadKind)expandedPayloadKind) == ODataPayloadKind.Feed;
            Func <object, string> func = null;

            if ((!flag && navigationLink.IsCollection.HasValue) && (expandedPayloadKind.HasValue && (flag2 != navigationLink.IsCollection.Value)))
            {
                func = (((ODataPayloadKind)expandedPayloadKind.Value) == ODataPayloadKind.Feed) ? new Func <object, string>(Microsoft.Data.OData.Strings.WriterValidationUtils_ExpandedLinkIsCollectionFalseWithFeedContent) : new Func <object, string>(Microsoft.Data.OData.Strings.WriterValidationUtils_ExpandedLinkIsCollectionTrueWithEntryContent);
            }
            IEdmType definition = null;

            if (declaringEntityType != null)
            {
                definition = ValidateNavigationPropertyDefined(navigationLink.Name, declaringEntityType).Type.Definition;
                bool flag3 = definition.TypeKind == EdmTypeKind.Collection;
                if (navigationLink.IsCollection.HasValue)
                {
                    bool flag4 = flag3;
                    if ((flag4 != navigationLink.IsCollection) && ((navigationLink.IsCollection != false) || !flag))
                    {
                        func = flag3 ? new Func <object, string>(Microsoft.Data.OData.Strings.WriterValidationUtils_ExpandedLinkIsCollectionFalseWithFeedMetadata) : new Func <object, string>(Microsoft.Data.OData.Strings.WriterValidationUtils_ExpandedLinkIsCollectionTrueWithEntryMetadata);
                    }
                }
                if ((!flag && expandedPayloadKind.HasValue) && (flag3 != flag2))
                {
                    func = flag3 ? new Func <object, string>(Microsoft.Data.OData.Strings.WriterValidationUtils_ExpandedLinkWithEntryPayloadAndFeedMetadata) : new Func <object, string>(Microsoft.Data.OData.Strings.WriterValidationUtils_ExpandedLinkWithFeedPayloadAndEntryMetadata);
                }
            }
            if (func != null)
            {
                string arg = (navigationLink.Url == null) ? "null" : UriUtilsCommon.UriToString(navigationLink.Url);
                throw new ODataException(func(arg));
            }
            return(definition);
        }
Пример #8
0
        private void CheckForNavigationLinkWithContent(ODataPayloadKind contentPayloadKind)
        {
            Scope currentScope = this.CurrentScope;

            if ((currentScope.State == WriterState.NavigationLink) || (currentScope.State == WriterState.NavigationLinkWithContent))
            {
                Action action = null;
                ODataNavigationLink currentNavigationLink  = (ODataNavigationLink)currentScope.Item;
                IEdmType            navigationPropertyType = null;
                this.InterceptException(delegate {
                    navigationPropertyType = WriterValidationUtils.ValidateNavigationLink(currentNavigationLink, this.ParentEntryEntityType, new ODataPayloadKind?(contentPayloadKind));
                    ((NavigationLinkScope)this.CurrentScope).NavigationPropertyType = navigationPropertyType;
                });
                if (currentScope.State != WriterState.NavigationLinkWithContent)
                {
                    this.PromoteNavigationLinkScope();
                    if (!this.SkipWriting)
                    {
                        if (action == null)
                        {
                            action = delegate {
                                this.DuplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(currentNavigationLink, contentPayloadKind != ODataPayloadKind.EntityReferenceLink, new bool?(contentPayloadKind == ODataPayloadKind.Feed));
                                this.StartNavigationLinkWithContent(currentNavigationLink);
                            };
                        }
                        this.InterceptException(action);
                    }
                }
                else if (this.outputContext.WritingResponse || (currentNavigationLink.IsCollection != true))
                {
                    this.ThrowODataException(Microsoft.Data.OData.Strings.ODataWriterCore_MultipleItemsInNavigationLinkContent, currentNavigationLink);
                }
            }
            else if (contentPayloadKind == ODataPayloadKind.EntityReferenceLink)
            {
                this.ThrowODataException(Microsoft.Data.OData.Strings.ODataWriterCore_EntityReferenceLinkWithoutNavigationLink, null);
            }
        }
        internal void CheckForDuplicatePropertyNames(ODataNavigationLink navigationLink, bool isExpanded, bool?isCollection)
        {
            DuplicationRecord record;
            string            name = navigationLink.Name;

            if (!this.TryGetDuplicationRecord(name, out record))
            {
                DuplicationRecord duplicationRecord = new DuplicationRecord(DuplicationKind.NavigationProperty);
                ApplyNavigationLinkToDuplicationRecord(duplicationRecord, isExpanded, isCollection);
                this.propertyNameCache.Add(name, duplicationRecord);
            }
            else
            {
                this.CheckNavigationLinkDuplicateNameForExistingDuplicationRecord(name, record);
                if (((record.DuplicationKind == DuplicationKind.NavigationProperty) && record.AssociationLinkFound) && !record.NavigationLinkFound)
                {
                    ApplyNavigationLinkToDuplicationRecord(record, isExpanded, isCollection);
                }
                else if (this.allowDuplicateProperties)
                {
                    record.DuplicationKind = DuplicationKind.NavigationProperty;
                    ApplyNavigationLinkToDuplicationRecord(record, isExpanded, isCollection);
                }
                else
                {
                    bool?isCollectionEffectiveValue = GetIsCollectionEffectiveValue(isExpanded, isCollection);
                    if ((isCollectionEffectiveValue == false) || (record.NavigationPropertyIsCollection == false))
                    {
                        throw new ODataException(Strings.DuplicatePropertyNamesChecker_MultipleLinksForSingleton(name));
                    }
                    if (isCollectionEffectiveValue.HasValue)
                    {
                        record.NavigationPropertyIsCollection = isCollectionEffectiveValue;
                    }
                }
            }
        }
Пример #10
0
 internal void CheckForDuplicatePropertyNames(ODataNavigationLink navigationLink, bool isExpanded, bool? isCollection)
 {
     DuplicationRecord record;
     string name = navigationLink.Name;
     if (!this.TryGetDuplicationRecord(name, out record))
     {
         DuplicationRecord duplicationRecord = new DuplicationRecord(DuplicationKind.NavigationProperty);
         ApplyNavigationLinkToDuplicationRecord(duplicationRecord, isExpanded, isCollection);
         this.propertyNameCache.Add(name, duplicationRecord);
     }
     else
     {
         this.CheckNavigationLinkDuplicateNameForExistingDuplicationRecord(name, record);
         if (((record.DuplicationKind == DuplicationKind.NavigationProperty) && record.AssociationLinkFound) && !record.NavigationLinkFound)
         {
             ApplyNavigationLinkToDuplicationRecord(record, isExpanded, isCollection);
         }
         else if (this.allowDuplicateProperties)
         {
             record.DuplicationKind = DuplicationKind.NavigationProperty;
             ApplyNavigationLinkToDuplicationRecord(record, isExpanded, isCollection);
         }
         else
         {
             bool? isCollectionEffectiveValue = GetIsCollectionEffectiveValue(isExpanded, isCollection);
             if ((isCollectionEffectiveValue == false) || (record.NavigationPropertyIsCollection == false))
             {
                 throw new ODataException(Strings.DuplicatePropertyNamesChecker_MultipleLinksForSingleton(name));
             }
             if (isCollectionEffectiveValue.HasValue)
             {
                 record.NavigationPropertyIsCollection = isCollectionEffectiveValue;
             }
         }
     }
 }
        private void WriteNavigationLinks(EntityInstanceContext context, ODataWriter writer, ODataSerializerContext writeContext)
        {
            foreach (IEdmNavigationProperty navProperty in _edmEntityTypeReference.NavigationProperties())
            {
                IEdmTypeReference propertyType = navProperty.Type;

                if (writeContext.EntitySet != null)
                {
                    IEntitySetLinkBuilder linkBuilder = SerializerProvider.EdmModel.GetEntitySetLinkBuilder(writeContext.EntitySet);

                    ODataNavigationLink navigationLink = new ODataNavigationLink
                    {
                        IsCollection = propertyType.IsCollection(),
                        Name = navProperty.Name,
                        Url = linkBuilder.BuildNavigationLink(context, navProperty)
                    };

                    writer.WriteStart(navigationLink);
                    writer.WriteEnd();
                }
            }
        }
Пример #12
0
 private void WriteStartNavigationLinkImplementation(ODataNavigationLink navigationLink)
 {
     this.EnterScope(WriterState.NavigationLink, navigationLink);
 }
Пример #13
0
        /// <summary>
        /// Verifies that calling WriteStart navigation link is valid.
        /// </summary>
        /// <param name="synchronousCall">true if the call is to be synchronous; false otherwise.</param>
        /// <param name="navigationLink">Navigation link to write.</param>
        private void VerifyCanWriteStartNavigationLink(bool synchronousCall, ODataNavigationLink navigationLink)
        {
            ExceptionUtils.CheckArgumentNotNull(navigationLink, "navigationLink");

            this.VerifyNotDisposed();
            this.VerifyCallAllowed(synchronousCall);
        }
Пример #14
0
 /// <summary>
 /// Finish writing a navigation link with content.
 /// </summary>
 /// <param name="navigationLink">The navigation link to write.</param>
 protected abstract void EndNavigationLinkWithContent(ODataNavigationLink navigationLink);
Пример #15
0
 /// <summary>
 /// Asynchronously start writing a navigation link.
 /// </summary>
 /// <param name="navigationLink">Navigation link to writer.</param>
 /// <returns>A task instance that represents the asynchronous write operation.</returns>
 public sealed override Task WriteStartAsync(ODataNavigationLink navigationLink)
 {
     this.VerifyCanWriteStartNavigationLink(false, navigationLink);
     return TaskUtils.GetTaskForSynchronousOperation(() => this.WriteStartNavigationLinkImplementation(navigationLink));
 }
Пример #16
0
 protected abstract void WriteEntityReferenceInNavigationLinkContent(ODataNavigationLink parentNavigationLink, ODataEntityReferenceLink entityReferenceLink);
Пример #17
0
 public abstract void WriteStart(ODataNavigationLink navigationLink);
Пример #18
0
 /// <summary>
 /// Asynchronously start writing a navigation link.
 /// </summary>
 /// <param name="navigationLink">Navigation link to writer.</param>
 /// <returns>A task instance that represents the asynchronous write operation.</returns>
 public abstract Task WriteStartAsync(ODataNavigationLink navigationLink);
        /// <summary>
        /// Reads a navigation link in entry element.
        /// </summary>
        /// <param name="entryState">The reader entry state for the entry being read.</param>
        /// <param name="linkRelation">The value of the rel attribute of the link to read, unescaped parsed URI.</param>
        /// <param name="linkHRef">The value of the href attribute of the link to read.</param>
        /// <returns>A descriptor of a navigation link if a navigation link was found; null otherwise.</returns>
        /// <remarks>
        /// Pre-Condition:  XmlNodeType.Element atom:link - the start tag of the atom:link element to read.
        /// Post-Condition: XmlNodeType.Element atom:link - the start tag of the atom:link element - the reader doesn't move
        /// </remarks>
        private ODataAtomReaderNavigationLinkDescriptor TryReadNavigationLinkInEntry(
            IODataAtomReaderEntryState entryState,
            string linkRelation,
            string linkHRef)
        {
            Debug.Assert(linkRelation != null, "linkRelation != null");
            this.XmlReader.AssertNotBuffering();
            this.AssertXmlCondition(XmlNodeType.Element);
            Debug.Assert(
                this.XmlReader.NamespaceURI == AtomConstants.AtomNamespace && this.XmlReader.LocalName == AtomConstants.AtomLinkElementName,
                "The XML reader must be on the atom:link element for this method to work.");

            string navigationLinkName = AtomUtils.GetNameFromAtomLinkRelationAttribute(linkRelation, AtomConstants.ODataNavigationPropertiesRelatedLinkRelationPrefix);
            if (string.IsNullOrEmpty(navigationLinkName))
            {
                return null;
            }

            // Lookup the property in metadata
            // Note that we already verified that the navigation link name is not empty.
            IEdmNavigationProperty navigationProperty = ReaderValidationUtils.ValidateNavigationPropertyDefined(navigationLinkName, entryState.EntityType, this.MessageReaderSettings);

            // Navigation link
            ODataNavigationLink navigationLink = new ODataNavigationLink { Name = navigationLinkName };

            // Get the type of the link
            string navigationLinkType = this.XmlReader.GetAttribute(this.AtomTypeAttributeName, this.EmptyNamespace);

            if (!string.IsNullOrEmpty(navigationLinkType))
            {
                // Fast path for most common link types
                bool hasEntryType, hasFeedType;
                bool isExactMatch = AtomUtils.IsExactNavigationLinkTypeMatch(navigationLinkType, out hasEntryType, out hasFeedType);
                if (!isExactMatch)
                {
                    // If the fast path did not work, we have to fully parse the media type.
                    string mediaTypeName, mediaTypeCharset;
                    IList<KeyValuePair<string, string>> contentTypeParameters = HttpUtils.ReadMimeType(navigationLinkType, out mediaTypeName, out mediaTypeCharset);
                    if (!HttpUtils.CompareMediaTypeNames(mediaTypeName, MimeConstants.MimeApplicationAtomXml))
                    {
                        return null;
                    }

                    string typeParameterValue = null;
                    if (contentTypeParameters != null)
                    {
                        for (int contentTypeParameterIndex = 0; contentTypeParameterIndex < contentTypeParameters.Count; contentTypeParameterIndex++)
                        {
                            KeyValuePair<string, string> contentTypeParameter = contentTypeParameters[contentTypeParameterIndex];
                            if (HttpUtils.CompareMediaTypeParameterNames(MimeConstants.MimeTypeParameterName, contentTypeParameter.Key))
                            {
                                typeParameterValue = contentTypeParameter.Value;
                                break;
                            }
                        }
                    }

                    if (typeParameterValue != null)
                    {
                        if (string.Compare(typeParameterValue, MimeConstants.MimeTypeParameterValueEntry, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            hasEntryType = true;
                        }
                        else if (string.Compare(typeParameterValue, MimeConstants.MimeTypeParameterValueFeed, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            hasFeedType = true;
                        }
                    }
                }

                if (hasEntryType)
                {
                    if (!this.UseClientFormatBehavior)
                    {
                        navigationLink.IsCollection = false;
                    }
                }
                else if (hasFeedType)
                {
                    navigationLink.IsCollection = true;
                }
            }

            if (linkHRef != null)
            {
                navigationLink.Url = this.ProcessUriFromPayload(linkHRef, this.XmlReader.XmlBaseUri);
            }

            this.XmlReader.MoveToElement();

            // Read and store ATOM link metadata (captures extra info like lang, title) if ATOM metadata reading is turned on.
            AtomLinkMetadata atomLinkMetadata = this.EntryMetadataDeserializer.ReadAtomLinkElementInEntryContent(linkRelation, linkHRef);
            if (atomLinkMetadata != null)
            {
                navigationLink.SetAnnotation(atomLinkMetadata);
            }

            return new ODataAtomReaderNavigationLinkDescriptor(navigationLink, navigationProperty);
        }
Пример #20
0
 protected abstract void EndNavigationLinkWithContent(ODataNavigationLink navigationLink);
Пример #21
0
        /// <summary>
        /// Sets the properties on a duplication record for a navigation link.
        /// </summary>
        /// <param name="duplicationRecord">The duplication record to modify.</param>
        /// <param name="navigationLink">The navigation link found for this property.</param>
        /// <param name="isExpanded">true if the navigation link is expanded, false otherwise.</param>
        /// <param name="isCollection">true if the navigation link is marked as collection, false if it's marked as singletong or null if we don't know.</param>
        private static void ApplyNavigationLinkToDuplicationRecord(DuplicationRecord duplicationRecord, ODataNavigationLink navigationLink, bool isExpanded, bool?isCollection)
        {
            duplicationRecord.DuplicationKind = DuplicationKind.NavigationProperty;
            duplicationRecord.NavigationLink  = navigationLink;

            // We only take the cardinality of the link for granted if it was expanded or if it is a collection.
            // We can't rely on singleton deferred links to know the cardinality since they can be used for binding even if the actual link is a collection.
            duplicationRecord.NavigationPropertyIsCollection = GetIsCollectionEffectiveValue(isExpanded, isCollection);
        }
Пример #22
0
 private void VerifyCanWriteStartNavigationLink(bool synchronousCall, ODataNavigationLink navigationLink)
 {
     ExceptionUtils.CheckArgumentNotNull <ODataNavigationLink>(navigationLink, "navigationLink");
     this.VerifyNotDisposed();
     this.VerifyCallAllowed(synchronousCall);
 }
Пример #23
0
 public sealed override void WriteStart(ODataNavigationLink navigationLink)
 {
     this.VerifyCanWriteStartNavigationLink(true, navigationLink);
     this.WriteStartNavigationLinkImplementation(navigationLink);
 }
Пример #24
0
        /// <summary>
        /// Starts the navigation link.
        /// Does metadata validation of the navigation link and sets up the reader to report it.
        /// </summary>
        /// <param name="navigationLink">The navigation link to start.</param>
        /// <param name="navigationProperty">The navigation property for the navigation link to start.</param>
        private void StartNavigationLink(ODataNavigationLink navigationLink, IEdmNavigationProperty navigationProperty)
        {
            Debug.Assert(
                this.jsonEntryAndFeedDeserializer.JsonReader.NodeType == JsonNodeType.StartObject ||
                this.jsonEntryAndFeedDeserializer.JsonReader.NodeType == JsonNodeType.StartArray ||
                this.jsonEntryAndFeedDeserializer.JsonReader.NodeType == JsonNodeType.PrimitiveValue && this.jsonEntryAndFeedDeserializer.JsonReader.Value == null,
                "Post-Condition: expected JsonNodeType.StartObject or JsonNodeType.StartArray or JsonNodeType.Primitive (null)");
            Debug.Assert(
                navigationProperty != null || this.jsonInputContext.MessageReaderSettings.UndeclaredPropertyBehaviorKinds.HasFlag(ODataUndeclaredPropertyBehaviorKinds.ReportUndeclaredLinkProperty),
                "A navigation property must be found for each link we find unless we're allowed to report undeclared links.");

            // we are at the beginning of a link
            Debug.Assert(!string.IsNullOrEmpty(navigationLink.Name), "Navigation links must have a name.");

            IEdmEntityType targetEntityType = null;
            if (navigationProperty != null)
            {
                IEdmTypeReference navigationPropertyType = navigationProperty.Type;
                targetEntityType = navigationPropertyType.IsCollection()
                    ? navigationPropertyType.AsCollection().ElementType().AsEntity().EntityDefinition()
                    : navigationPropertyType.AsEntity().EntityDefinition();
            }

            this.EnterScope(ODataReaderState.NavigationLinkStart, navigationLink, targetEntityType);
        }
Пример #25
0
 /// <summary>
 /// Start writing a navigation link.
 /// </summary>
 /// <param name="navigationLink">Navigation link to write.</param>
 public abstract void WriteStart(ODataNavigationLink navigationLink);
Пример #26
0
 internal NavigationLinkScope(ODataWriterCore.WriterState writerState, ODataNavigationLink navLink, bool skipWriting) : base(writerState, navLink, skipWriting)
 {
 }
 /// <summary>
 /// Initializes a new instance of <see cref="ODataNavigationLinkWithItems"/>.
 /// </summary>
 /// <param name="item">The wrapped item.</param>
 public ODataNavigationLinkWithItems(ODataNavigationLink item)
     : base(item)
 {
     NestedItems = new List<ODataItemBase>();
 }
        /// <summary>
        /// Check the <paramref name="navigationLink"/> for duplicate property names in an entry or complex value.
        /// If not explicitly allowed throw when duplicate properties are detected.
        /// If duplicate properties are allowed see the comment on ODataWriterBehavior.AllowDuplicatePropertyNames
        /// or ODataReaderBehavior.AllowDuplicatePropertyNames for further details.
        /// </summary>
        /// <param name="navigationLink">The navigation link to be checked.</param>
        /// <param name="isExpanded">true if the link is expanded, false otherwise.</param>
        /// <param name="isCollection">true if the navigation link is a collection, false if it's a singleton or null if we don't know.</param>
        internal void CheckForDuplicatePropertyNames(ODataNavigationLink navigationLink, bool isExpanded, bool?isCollection)
        {
            DebugUtils.CheckNoExternalCallers();
#if DEBUG
            this.startNavigationLinkName = null;
#endif

            string            propertyName = navigationLink.Name;
            DuplicationRecord existingDuplicationRecord;
            if (!this.TryGetDuplicationRecord(propertyName, out existingDuplicationRecord))
            {
                DuplicationRecord duplicationRecord = new DuplicationRecord(DuplicationKind.NavigationProperty);
                ApplyNavigationLinkToDuplicationRecord(duplicationRecord, isExpanded, isCollection);
                this.propertyNameCache.Add(propertyName, duplicationRecord);
            }
            else
            {
                // First check for duplication without expansion knowledge.
                this.CheckNavigationLinkDuplicateNameForExistingDuplicationRecord(propertyName, existingDuplicationRecord);

                if (existingDuplicationRecord.DuplicationKind == DuplicationKind.NavigationProperty &&
                    existingDuplicationRecord.AssociationLinkFound &&
                    !existingDuplicationRecord.NavigationLinkFound)
                {
                    // If the existing one is just an association link, update it to include the navigation link portion as well
                    ApplyNavigationLinkToDuplicationRecord(existingDuplicationRecord, isExpanded, isCollection);
                }
                else if (this.allowDuplicateProperties)
                {
                    Debug.Assert(
                        (existingDuplicationRecord.DuplicationKind == DuplicationKind.PotentiallyAllowed || existingDuplicationRecord.DuplicationKind == DuplicationKind.NavigationProperty),
                        "We should have already taken care of prohibit duplication.");

                    // If the configuration explicitly allows duplication, then just turn the existing property into a nav link with all the information we have
                    existingDuplicationRecord.DuplicationKind = DuplicationKind.NavigationProperty;
                    ApplyNavigationLinkToDuplicationRecord(existingDuplicationRecord, isExpanded, isCollection);
                }
                else
                {
                    // We've found two navigation links in a request
                    Debug.Assert(
                        existingDuplicationRecord.DuplicationKind == DuplicationKind.NavigationProperty && existingDuplicationRecord.NavigationLinkFound && !this.isResponse,
                        "We can only get here if we've found two navigation links in a request.");

                    bool?isCollectionEffectiveValue = GetIsCollectionEffectiveValue(isExpanded, isCollection);

                    // If one of them is a definitive singleton, then we fail.
                    if (isCollectionEffectiveValue == false || existingDuplicationRecord.NavigationPropertyIsCollection == false)
                    {
                        // This is the case where an expanded singleton is followed by a deferred link for example.
                        // Once we know for sure that the nav. prop. is a singleton we can't allow more than one link for it.
                        throw new ODataException(Strings.DuplicatePropertyNamesChecker_MultipleLinksForSingleton(propertyName));
                    }

                    // Otherwise allow it, but update the link with the new information
                    if (isCollectionEffectiveValue.HasValue)
                    {
                        existingDuplicationRecord.NavigationPropertyIsCollection = isCollectionEffectiveValue;
                    }
                }
            }
        }
 internal void WriteNavigationLinkStart(ODataNavigationLink navigationLink, Uri navigationLinkUrlOverride)
 {
     base.XmlWriter.WriteStartElement("", "link", "http://www.w3.org/2005/Atom");
     string relation = AtomUtils.ComputeODataNavigationLinkRelation(navigationLink);
     string mediaType = AtomUtils.ComputeODataNavigationLinkType(navigationLink);
     string name = navigationLink.Name;
     Uri href = navigationLinkUrlOverride ?? navigationLink.Url;
     AtomLinkMetadata linkMetadata = ODataAtomWriterMetadataUtils.MergeLinkMetadata(navigationLink.GetAnnotation<AtomLinkMetadata>(), relation, href, name, mediaType);
     this.atomEntryMetadataSerializer.WriteAtomLinkAttributes(linkMetadata, null);
 }
Пример #30
0
        internal static IEdmType ValidateNavigationLink(ODataNavigationLink navigationLink, IEdmEntityType declaringEntityType, ODataPayloadKind?expandedPayloadKind)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(navigationLink != null, "navigationLink != null");
            Debug.Assert(
                !expandedPayloadKind.HasValue ||
                expandedPayloadKind.Value == ODataPayloadKind.EntityReferenceLink ||
                expandedPayloadKind.Value == ODataPayloadKind.Entry ||
                expandedPayloadKind.Value == ODataPayloadKind.Feed,
                "If an expanded payload kind is specified it must be entry, feed or entity reference link.");

            // Navigation link must have a non-empty name
            if (string.IsNullOrEmpty(navigationLink.Name))
            {
                throw new ODataException(Strings.ValidationUtils_LinkMustSpecifyName);
            }

            // If we write an entity reference link, don't validate the multiplicity of the IsCollection
            // property if it is 'false' (since we allow writing a singleton navigation link for
            // a colleciton navigation property in requests) nor the consistency of payload kind and metadata
            // (which is done separately in ODataWriterCore.CheckForNavigationLinkWithContent).
            bool isEntityReferenceLinkPayload = expandedPayloadKind == ODataPayloadKind.EntityReferenceLink;

            // true only if the expandedPayloadKind has a value and the value is 'Feed'
            bool isFeedPayload = expandedPayloadKind == ODataPayloadKind.Feed;

            // Make sure the IsCollection property agrees with the payload kind for entry and feed payloads
            Func <object, string> errorTemplate = null;

            if (!isEntityReferenceLinkPayload && navigationLink.IsCollection.HasValue && expandedPayloadKind.HasValue)
            {
                // For feed/entry make sure the IsCollection property is set correctly.
                if (isFeedPayload != navigationLink.IsCollection.Value)
                {
                    errorTemplate = expandedPayloadKind.Value == ODataPayloadKind.Feed
                        ? (Func <object, string>)Strings.WriterValidationUtils_ExpandedLinkIsCollectionFalseWithFeedContent
                        : Strings.WriterValidationUtils_ExpandedLinkIsCollectionTrueWithEntryContent;
                }
            }

            IEdmType navigationPropertyType = null;

            if (declaringEntityType != null)
            {
                IEdmProperty navigationProperty = WriterValidationUtils.ValidateNavigationPropertyDefined(navigationLink.Name, declaringEntityType);
                Debug.Assert(navigationProperty != null, "If we have a declaring type we expect a non-null navigation property since open nav props are not allowed.");

                navigationPropertyType = navigationProperty.Type.Definition;
                bool isCollectionType = navigationPropertyType.TypeKind == EdmTypeKind.Collection;

                // Make sure the IsCollection property agrees with the metadata type for entry and feed payloads
                if (navigationLink.IsCollection.HasValue && isCollectionType != navigationLink.IsCollection)
                {
                    // Ignore the case where IsCollection is 'false' and we are writing an entity reference link
                    // (see comment above)
                    if (!(navigationLink.IsCollection == false && isEntityReferenceLinkPayload))
                    {
                        errorTemplate = isCollectionType
                            ? (Func <object, string>)Strings.WriterValidationUtils_ExpandedLinkIsCollectionFalseWithFeedMetadata
                            : Strings.WriterValidationUtils_ExpandedLinkIsCollectionTrueWithEntryMetadata;
                    }
                }

                // Make sure that the payload kind agrees with the metadata.
                // For entity reference links we check separately in ODataWriterCore.CheckForNavigationLinkWithContent.
                if (!isEntityReferenceLinkPayload && expandedPayloadKind.HasValue && isCollectionType != isFeedPayload)
                {
                    errorTemplate = isCollectionType
                        ? (Func <object, string>)Strings.WriterValidationUtils_ExpandedLinkWithEntryPayloadAndFeedMetadata
                        : Strings.WriterValidationUtils_ExpandedLinkWithFeedPayloadAndEntryMetadata;
                }
            }

            if (errorTemplate != null)
            {
                string uri = navigationLink.Url == null ? "null" : UriUtilsCommon.UriToString(navigationLink.Url);
                throw new ODataException(errorTemplate(uri));
            }

            return(navigationPropertyType);
        }
Пример #31
0
 public abstract Task WriteStartAsync(ODataNavigationLink navigationLink);
Пример #32
0
 /// <summary>
 /// Constructor to create a new navigation link scope.
 /// </summary>
 /// <param name="writerState">The writer state for the new scope.</param>
 /// <param name="navLink">The navigation link for the new scope.</param>
 /// <param name="skipWriting">true if the content of the scope to create should not be written.</param>
 internal NavigationLinkScope(WriterState writerState, ODataNavigationLink navLink, bool skipWriting)
     : base(writerState, navLink, skipWriting)
 {
     DebugUtils.CheckNoExternalCallers();
 }
Пример #33
0
 private IEnumerable<PropertyInfo> WriteNavigationLinks(ODataWriter entryWriter, Uri entryLink, IGraph resultsGraph,
                                                 string entryResource, string entryType)
 {
     var subject = resultsGraph.CreateUriNode(UriFactory.Create(entryResource));
     var navigableProperties = new List<PropertyInfo>();
     foreach (var assocMap in _map.GetAssociationPropertyMappings(entryType))
     {
         var predicate = resultsGraph.CreateUriNode(UriFactory.Create(assocMap.Uri));
         List<Triple> matches = assocMap.IsInverse
                                    ? resultsGraph.GetTriplesWithPredicateObject(predicate, subject).ToList()
                                    : resultsGraph.GetTriplesWithSubjectPredicate(subject, predicate).ToList();
         if (matches.Any(t => t.Object is UriNode)) // Ignore literal and blank nodes as these cannot be entities
         {
             var navLink = new ODataNavigationLink
                 {
                     IsCollection = assocMap.IsCollection,
                     Name = assocMap.Name,
                     Url = new Uri(entryLink + "/" + assocMap.Name)
                 };
             entryWriter.WriteStart(navLink);
             entryWriter.WriteEnd();
             navigableProperties.Add(assocMap);
         }
     }
     return navigableProperties;
 }
Пример #34
0
 protected abstract void WriteDeferredNavigationLink(ODataNavigationLink navigationLink);
Пример #35
0
 private void StartNavigationLink(ODataNavigationLink navigationLink, IEdmNavigationProperty navigationProperty)
 {
     IEdmEntityType expectedEntityType = null;
     if (navigationProperty != null)
     {
         IEdmTypeReference type = navigationProperty.Type;
         expectedEntityType = type.IsCollection() ? type.AsCollection().ElementType().AsEntity().EntityDefinition() : type.AsEntity().EntityDefinition();
     }
     this.EnterScope(ODataReaderState.NavigationLinkStart, navigationLink, expectedEntityType);
 }
Пример #36
0
 protected override void WriteEntityReferenceInNavigationLinkContent(ODataNavigationLink parentNavigationLink, ODataEntityReferenceLink entityReferenceLink)
 {
     this.WriteNavigationLinkStart(parentNavigationLink, entityReferenceLink.Url);
     this.WriteNavigationLinkEnd();
 }
Пример #37
0
 /// <summary>
 /// Start writing a navigation link.
 /// </summary>
 /// <param name="navigationLink">Navigation link to write.</param>
 public sealed override void WriteStart(ODataNavigationLink navigationLink)
 {
     this.VerifyCanWriteStartNavigationLink(true, navigationLink);
     this.WriteStartNavigationLinkImplementation(navigationLink);
 }
Пример #38
0
 private void WriteNavigationLinkStart(ODataNavigationLink navigationLink, Uri navigationLinkUrlOverride)
 {
     if (!navigationLink.IsCollection.HasValue)
     {
         throw new ODataException(Microsoft.Data.OData.Strings.ODataWriterCore_LinkMustSpecifyIsCollection);
     }
     if (navigationLink.Url == null)
     {
         throw new ODataException(Microsoft.Data.OData.Strings.ODataWriter_NavigationLinkMustSpecifyUrl);
     }
     this.atomEntryAndFeedSerializer.WriteNavigationLinkStart(navigationLink, navigationLinkUrlOverride);
 }
Пример #39
0
 /// <summary>
 /// Write a deferred (non-expanded) navigation link.
 /// </summary>
 /// <param name="navigationLink">The navigation link to write.</param>
 protected abstract void WriteDeferredNavigationLink(ODataNavigationLink navigationLink);
Пример #40
0
        /// <summary>
        /// Start writing a navigation link.
        /// </summary>
        /// <param name="navigationLink">The navigation link to write.</param>
        protected override void WriteDeferredNavigationLink(ODataNavigationLink navigationLink)
        {
            Debug.Assert(navigationLink != null, "navigationLink != null");
            Debug.Assert(this.atomOutputContext.WritingResponse, "Deferred links are only supported in response, we should have verified this already.");

            this.WriteNavigationLinkStart(navigationLink, null);
            this.WriteNavigationLinkEnd();
        }
Пример #41
0
 /// <summary>
 /// Write an entity reference link into a navigation link content.
 /// </summary>
 /// <param name="parentNavigationLink">The parent navigation link which is being written around the entity reference link.</param>
 /// <param name="entityReferenceLink">The entity reference link to write.</param>
 protected abstract void WriteEntityReferenceInNavigationLinkContent(ODataNavigationLink parentNavigationLink, ODataEntityReferenceLink entityReferenceLink);
Пример #42
0
        /// <summary>
        /// Start writing a navigation link with content.
        /// </summary>
        /// <param name="navigationLink">The navigation link to write.</param>
        protected override void StartNavigationLinkWithContent(ODataNavigationLink navigationLink)
        {
            Debug.Assert(navigationLink != null, "navigationLink != null");

            // In requests, a navigation link can have multiple items in its content (in the OM view), either entity reference links or expanded entry/feed.
            // For each of these we need to write a separate atom:link element. So we can't write the start of the atom:link element here
            // instead we postpone writing it till the first item in the content.
            // In response, only one item can occur, but for simplicity we will keep the behavior the same as for request and thus postpone writing the atom:link
            // start element as well.
            // Note that the writer core guarantees that this method (and the matching EndNavigationLinkWithContent) is only called for navigation links
            // which actually have some content. The only case where navigation link doesn't have a content is in response, in which case this method won't
            // be called, instead the WriteDeferredNavigationLink is called.
        }
Пример #43
0
 /// <summary>
 /// Start writing a navigation link - implementation of the actual functionality.
 /// </summary>
 /// <param name="navigationLink">Navigation link to write.</param>
 private void WriteStartNavigationLinkImplementation(ODataNavigationLink navigationLink)
 {
     this.EnterScope(WriterState.NavigationLink, navigationLink);
 }
Пример #44
0
        /// <summary>
        /// Finish writing a navigation link with content.
        /// </summary>
        /// <param name="navigationLink">The navigation link to write.</param>
        protected override void EndNavigationLinkWithContent(ODataNavigationLink navigationLink)
        {
            Debug.Assert(navigationLink != null, "navigationLink != null");

            // We do not write the end element for atom:link here, since we need to write it for each item in the content separately.
            // See the detailed description in the StartNavigationLinkWithContent for details.
        }
        /// <summary>
        /// Creates the <see cref="ODataNavigationLink"/> to be written while writing this entity.
        /// </summary>
        /// <param name="navigationProperty">The navigation property for which the navigation link is being created.</param>
        /// <param name="entityInstanceContext">The context for the entity instance being written.</param>
        /// <returns>The navigation link to be written.</returns>
        public virtual ODataNavigationLink CreateNavigationLink(IEdmNavigationProperty navigationProperty, EntityInstanceContext entityInstanceContext)
        {
            if (navigationProperty == null)
            {
                throw Error.ArgumentNull("navigationProperty");
            }
            if (entityInstanceContext == null)
            {
                throw Error.ArgumentNull("entityInstanceContext");
            }

            ODataSerializerContext writeContext = entityInstanceContext.SerializerContext;
            ODataNavigationLink navigationLink = null;

            if (writeContext.EntitySet != null)
            {
                IEdmTypeReference propertyType = navigationProperty.Type;
                IEdmModel model = writeContext.Model;
                EntitySetLinkBuilderAnnotation linkBuilder = model.GetEntitySetLinkBuilder(writeContext.EntitySet);
                Uri navigationUrl = linkBuilder.BuildNavigationLink(entityInstanceContext, navigationProperty, writeContext.MetadataLevel);

                navigationLink = new ODataNavigationLink
                {
                    IsCollection = propertyType.IsCollection(),
                    Name = navigationProperty.Name,
                };

                if (navigationUrl != null)
                {
                    navigationLink.Url = navigationUrl;
                }
            }

            return navigationLink;
        }
Пример #46
0
        /// <summary>
        /// Write an entity reference link.
        /// </summary>
        /// <param name="parentNavigationLink">The parent navigation link which is being written around the entity reference link.</param>
        /// <param name="entityReferenceLink">The entity reference link to write.</param>
        protected override void WriteEntityReferenceInNavigationLinkContent(ODataNavigationLink parentNavigationLink, ODataEntityReferenceLink entityReferenceLink)
        {
            Debug.Assert(parentNavigationLink != null, "parentNavigationLink != null");
            Debug.Assert(entityReferenceLink != null, "entityReferenceLink != null");
            Debug.Assert(entityReferenceLink.Url != null, "We should have already verifies that the Url specified on the entity reference link is not null.");

            this.WriteNavigationLinkStart(parentNavigationLink, entityReferenceLink.Url);
            this.WriteNavigationLinkEnd();
        }
        /// <summary>
        /// Creates the collection of <see cref="ODataNavigationLink"/>s to be written while writing this entity.
        /// </summary>
        /// <param name="entityInstanceContext">The context for the entity instance being written.</param>
        /// <param name="writeContext">The serializer write context.</param>
        /// <returns>The collection of navigation links to be written.</returns>
        public virtual IEnumerable<ODataNavigationLink> CreateNavigationLinks(EntityInstanceContext entityInstanceContext, ODataSerializerContext writeContext)
        {
            if (writeContext == null)
            {
                throw Error.ArgumentNull("writeContext");
            }

            foreach (IEdmNavigationProperty navProperty in EntityType.NavigationProperties())
            {
                IEdmTypeReference propertyType = navProperty.Type;

                if (writeContext.EntitySet != null)
                {
                    IEdmModel model = writeContext.Model;
                    EntitySetLinkBuilderAnnotation linkBuilder = model.GetEntitySetLinkBuilder(writeContext.EntitySet);
                    Uri navigationUrl = linkBuilder.BuildNavigationLink(entityInstanceContext, navProperty, writeContext.MetadataLevel);

                    ODataNavigationLink navigationLink = new ODataNavigationLink
                    {
                        IsCollection = propertyType.IsCollection(),
                        Name = navProperty.Name,
                    };

                    if (navigationUrl != null)
                    {
                        navigationLink.Url = navigationUrl;
                    }

                    yield return navigationLink;
                }
            }
        }
Пример #48
0
        /// <summary>
        /// Writes the navigation link's start element and atom metadata.
        /// </summary>
        /// <param name="navigationLink">The navigation link to write.</param>
        /// <param name="navigationLinkUrlOverride">Url to use for the navigation link. If this is specified the Url property on the <paramref name="navigationLink"/>
        /// will be ignored. If this parameter is null, the Url from the navigation link is used.</param>
        private void WriteNavigationLinkStart(ODataNavigationLink navigationLink, Uri navigationLinkUrlOverride)
        {
            // IsCollection is required for ATOM
            if (!navigationLink.IsCollection.HasValue)
            {
                throw new ODataException(o.Strings.ODataWriterCore_LinkMustSpecifyIsCollection);
            }

            // Navigation link must specify the Url
            // NOTE: we currently only require a non-null Url for ATOM payloads and non-expanded navigation links in JSON.
            //       There is no place in JSON to write a Url if the navigation link is expanded. We can't change that for v1 and v2; we
            //       might fix the protocol for v3.
            if (navigationLink.Url == null)
            {
                throw new ODataException(o.Strings.ODataWriter_NavigationLinkMustSpecifyUrl);
            }

            this.atomEntryAndFeedSerializer.WriteNavigationLinkStart(navigationLink, navigationLinkUrlOverride);
        }