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; } } } }
/// <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; } } } }