Exemplo n.º 1
0
        public void GetOrCreateReadOnlyEnumerableShouldGetForReadOnlyEnumerableSource()
        {
            var enumerable  = new ReadOnlyEnumerable <int>();
            var enumerable2 = enumerable.GetOrCreateReadOnlyEnumerable("Integers");

            enumerable2.As <object>().Should().NotBeSameAs(ReadOnlyEnumerable <int> .Empty());
            enumerable2.As <object>().Should().BeSameAs(enumerable);
        }
Exemplo n.º 2
0
        public void ConcatToReadOnlyEnumerableShouldAddForReadOnlyEnumerableSource()
        {
            var enumerable = new ReadOnlyEnumerable <ODataProperty>();

            enumerable.Count().Should().Be(0);
            enumerable.ConcatToReadOnlyEnumerable("Properties", new ODataProperty());
            enumerable.Count().Should().Be(1);
        }
Exemplo n.º 3
0
        public void ConcatToReadOnlyEnumerableShouldAddForReadOnlyEnumerableSource()
        {
            var enumerable = new ReadOnlyEnumerable <ODataProperty>();

            Assert.Empty(enumerable);
            enumerable.ConcatToReadOnlyEnumerable("Properties", new ODataProperty());
            Assert.Single(enumerable);
        }
Exemplo n.º 4
0
        public void GetOrCreateReadOnlyEnumerableShouldGetForReadOnlyEnumerableSource()
        {
            var enumerable  = new ReadOnlyEnumerable <int>();
            var enumerable2 = enumerable.GetOrCreateReadOnlyEnumerable("Integers");

            Assert.NotSame(enumerable2, ReadOnlyEnumerable <int> .Empty());
            Assert.Same(enumerable2, enumerable);
        }
 public void AddToSourceListShouldAddToTheSourceList()
 {
     ReadOnlyEnumerable<int> enumerable = new ReadOnlyEnumerable<int>();
     enumerable.Should().BeEmpty();
     enumerable.AddToSourceList(1);
     enumerable.Count().Should().Be(1);
     enumerable.Should().OnlyContain(i => i == 1);
 }
 /// <summary>
 /// Reads the content of a properties in an element (complex value, m:properties, ...)
 /// </summary>
 /// <param name="structuredType">The type which should declare the properties to be read. Optional.</param>
 /// <param name="properties">The list of properties to add properties to.</param>
 /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use.</param>
 /// <remarks>
 /// Pre-Condition:  XmlNodeType.Element    - The element to read properties from.
 /// Post-Condition: XmlNodeType.Element    - The element to read properties from if it is an empty element.
 ///                 XmlNodeType.EndElement - The end element of the element to read properties from.
 /// </remarks>
 protected void ReadProperties(IEdmStructuredType structuredType, ReadOnlyEnumerable <ODataProperty> properties, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
 {
     this.AssertRecursionDepthIsZero();
     this.ReadPropertiesImplementation(
         structuredType,
         properties,
         duplicatePropertyNamesChecker);
     this.AssertRecursionDepthIsZero();
 }
Exemplo n.º 7
0
        public void ConcatToReadOnlyEnumerableShouldCreateReadOnlyEnumerableAndAddForEmptySource()
        {
            var enumerable = ReadOnlyEnumerable <ODataProperty> .Empty();

            var enumerable2 = enumerable.ConcatToReadOnlyEnumerable("Properties", new ODataProperty());

            enumerable2.As <object>().Should().NotBeSameAs(enumerable);
            enumerable2.Count().Should().Be(1);
        }
Exemplo n.º 8
0
        public void ConcatToReadOnlyEnumerableShouldCreateReadOnlyEnumerableAndAddForEmptySource()
        {
            var enumerable = ReadOnlyEnumerable <ODataProperty> .Empty();

            var enumerable2 = enumerable.ConcatToReadOnlyEnumerable("Properties", new ODataProperty());

            Assert.NotSame(enumerable2, enumerable);
            Assert.Single(enumerable2);
        }
Exemplo n.º 9
0
        public void GetOrCreateReadOnlyEnumerableShouldCreateForEmptyReadOnlyEnumerableSource()
        {
            var enumerable = ReadOnlyEnumerable <int> .Empty();

            var enumerable2 = enumerable.GetOrCreateReadOnlyEnumerable("Integers");

            Assert.NotSame(enumerable2, ReadOnlyEnumerable <int> .Empty());
            Assert.NotNull(enumerable2);
        }
Exemplo n.º 10
0
        public void AddToSourceListShouldAddToTheSourceList()
        {
            ReadOnlyEnumerable <int> enumerable = new ReadOnlyEnumerable <int>();

            enumerable.Should().BeEmpty();
            enumerable.AddToSourceList(1);
            enumerable.Count().Should().Be(1);
            enumerable.Should().OnlyContain(i => i == 1);
        }
Exemplo n.º 11
0
        public void AddToSourceListShouldAddToTheSourceList()
        {
            ReadOnlyEnumerable <int> enumerable = new ReadOnlyEnumerable <int>();

            Assert.Empty(enumerable);
            enumerable.AddToSourceList(1);
            int value = Assert.Single(enumerable);

            Assert.Equal(1, value);
        }
Exemplo n.º 12
0
        /// <summary>
        /// Reads EPM values from a person construct (author or contributor).
        /// </summary>
        /// <param name="targetList">The target list, this can be either a list of properties (on entry or complex value),
        /// or a list of items (for a collection of primitive types).</param>
        /// <param name="targetTypeReference">The type of the value on which to set the property (can be entity, complex or primitive).</param>
        /// <param name="targetSegment">The target segment which points to either author or contributor element.</param>
        /// <param name="personMetadata">The person ATOM metadata to read from.</param>
        private void ReadPersonEpm(ReadOnlyEnumerable <ODataProperty> targetList, IEdmTypeReference targetTypeReference, EpmTargetPathSegment targetSegment, AtomPersonMetadata personMetadata)
        {
            Debug.Assert(targetList != null, "targetList != null");
            Debug.Assert(targetTypeReference != null, "targetTypeReference != null");
            Debug.Assert(targetSegment != null, "targetSegment != null");
            Debug.Assert(
                targetSegment.SegmentName == AtomConstants.AtomAuthorElementName || targetSegment.SegmentName == AtomConstants.AtomContributorElementName,
                "targetSegment must be author or contributor.");
            Debug.Assert(personMetadata != null, "personMetadata != null");

            foreach (EpmTargetPathSegment subSegment in targetSegment.SubSegments)
            {
                Debug.Assert(subSegment.HasContent, "sub segment of author segment must have content, there are no subsegments which don't have content under author.");
                Debug.Assert(
                    subSegment.EpmInfo != null && subSegment.EpmInfo.Attribute != null && subSegment.EpmInfo.Attribute.TargetSyndicationItem != SyndicationItemProperty.CustomProperty,
                    "We should never find a subsegment without EPM attribute or for custom mapping when writing syndication person EPM.");
                switch (subSegment.EpmInfo.Attribute.TargetSyndicationItem)
                {
                case SyndicationItemProperty.AuthorName:
                case SyndicationItemProperty.ContributorName:
                    // Note that person name can never specify true null in EPM, since it can't have the m:null attribute on it.
                    string personName = personMetadata.Name;
                    if (personName != null)
                    {
                        this.SetEpmValue(targetList, targetTypeReference, subSegment.EpmInfo, personName);
                    }

                    break;

                case SyndicationItemProperty.AuthorEmail:
                case SyndicationItemProperty.ContributorEmail:
                    string personEmail = personMetadata.Email;
                    if (personEmail != null)
                    {
                        this.SetEpmValue(targetList, targetTypeReference, subSegment.EpmInfo, personEmail);
                    }

                    break;

                case SyndicationItemProperty.AuthorUri:
                case SyndicationItemProperty.ContributorUri:
                    string personUri = personMetadata.UriFromEpm;
                    if (personUri != null)
                    {
                        this.SetEpmValue(targetList, targetTypeReference, subSegment.EpmInfo, personUri);
                    }

                    break;

                default:
                    // Unhandled EpmTargetPathSegment.SegmentName.
                    throw new ODataException(ODataErrorStrings.General_InternalError(InternalErrorCodes.EpmSyndicationReader_ReadPersonEpm));
                }
            }
        }
        /// <summary>
        /// Read a complex value from the reader.
        /// </summary>
        /// <param name="complexTypeReference">The type reference of the value to read (or null if no type is available).</param>
        /// <param name="payloadTypeName">The name of the type specified in the payload.</param>
        /// <param name="serializationTypeNameAnnotation">The serialization type name for the complex value (possibly null).</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use (cached), or null if new one should be created.</param>
        /// <param name="epmPresent">Whether any EPM mappings exist.</param>
        /// <returns>The value read from the payload.</returns>
        /// <remarks>
        /// Pre-Condition:   XmlNodeType.Element   - the element to read the value for.
        ///                  XmlNodeType.Attribute - an attribute on the element to read the value for.
        /// Post-Condition:  XmlNodeType.EndElement - the element has been read.
        ///
        /// Note that this method will not read null values, those should be handled by the caller already.
        /// </remarks>
        private ODataComplexValue ReadComplexValue(
            IEdmComplexTypeReference complexTypeReference,
            string payloadTypeName,
            SerializationTypeNameAnnotation serializationTypeNameAnnotation,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            bool epmPresent)
        {
            this.AssertXmlCondition(XmlNodeType.Element, XmlNodeType.Attribute);

            this.IncreaseRecursionDepth();

            ODataComplexValue complexValue = new ODataComplexValue();
            IEdmComplexType   complexType  = complexTypeReference == null ? null : (IEdmComplexType)complexTypeReference.Definition;

            // If we have a metadata type for the complex value, use that type name
            // otherwise use the type name from the payload (if there was any).
            complexValue.TypeName = complexType == null ? payloadTypeName : complexType.ODataFullName();
            if (serializationTypeNameAnnotation != null)
            {
                complexValue.SetAnnotation(serializationTypeNameAnnotation);
            }

            // Move to the element (so that if we were on an attribute we can test the element for being empty)
            this.XmlReader.MoveToElement();

            if (duplicatePropertyNamesChecker == null)
            {
                duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker();
            }
            else
            {
                duplicatePropertyNamesChecker.Clear();
            }

            ReadOnlyEnumerable <ODataProperty> properties = new ReadOnlyEnumerable <ODataProperty>();

            this.ReadPropertiesImplementation(complexType, properties, duplicatePropertyNamesChecker, epmPresent);
            complexValue.Properties = properties;

            this.AssertXmlCondition(true, XmlNodeType.EndElement);
            Debug.Assert(complexValue != null, "The method should never return null since it doesn't handle null values.");

            this.DecreaseRecursionDepth();

            return(complexValue);
        }
Exemplo n.º 14
0
        /// <summary>
        /// Creates and adds a new property to the list of properties for an EPM.
        /// </summary>
        /// <param name="properties">The list of properties to add the property to.</param>
        /// <param name="propertyName">The name of the property to add.</param>
        /// <param name="propertyValue">The value of the property to add.</param>
        /// <param name="checkDuplicateEntryPropertyNames">true if the new property should be checked for duplicates against the entry properties; false otherwise.
        /// This should be true if the <paramref name="properties"/> is the list of properties for the entry, and false in all other cases.</param>
        private void AddEpmPropertyValue(ReadOnlyEnumerable <ODataProperty> properties, string propertyName, object propertyValue, bool checkDuplicateEntryPropertyNames)
        {
            Debug.Assert(properties != null, "properties != null");
            Debug.Assert(!string.IsNullOrEmpty(propertyName), "propertyName must not be null or empty.");

            // Create a new property object and add it.
            ODataProperty property = new ODataProperty
            {
                Name  = propertyName,
                Value = propertyValue
            };

            if (checkDuplicateEntryPropertyNames)
            {
                this.entryState.DuplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property);
            }

            properties.AddToSourceList(property);
        }
Exemplo n.º 15
0
        /// <summary>
        /// Sets the value read from EPM to a property on an entry.
        /// </summary>
        /// <param name="targetList">The target list, which is a list of properties (on entry or complex value).</param>
        /// <param name="targetTypeReference">The type of the value on which to set the property (can be entity or complex).</param>
        /// <param name="epmInfo">The EPM info for the mapping for which the value was read.</param>
        /// <param name="propertyValue">The property value read, if the value was specified as null then this should be null,
        /// if the value was missing the method should not be called at all.
        /// For primitive properties this should be the string value, for all other properties this should be the exact value type.</param>
        protected void SetEpmValue(
            ReadOnlyEnumerable <ODataProperty> targetList,
            IEdmTypeReference targetTypeReference,
            EntityPropertyMappingInfo epmInfo,
            object propertyValue)
        {
            Debug.Assert(epmInfo != null, "epmInfo != null");
            Debug.Assert(targetTypeReference != null, "targetTypeReference != null");
            Debug.Assert(targetList != null, "targetList != null");
            Debug.Assert(
                targetTypeReference.IsODataEntityTypeKind() || targetTypeReference.IsODataComplexTypeKind(),
                "Only entity and complex types can have an EPM value set on them.");

            this.SetEpmValueForSegment(
                epmInfo,
                0,
                targetTypeReference.AsStructuredOrNull(),
                targetList,
                propertyValue);
        }
Exemplo n.º 16
0
        /// <summary>
        /// Full constructor.
        /// </summary>
        /// <param name="communicationsServer">The <see cref="ISsdpCommunicationsServer"/> implementation, used to send and receive SSDP network messages.</param>
        /// <param name="osName">Then name of the operating system running the server.</param>
        /// <param name="osVersion">The version of the operating system running the server.</param>
        /// <param name="log">An implementation of <see cref="ISsdpLogger"/> to be used for logging activity. May be null, in which case no logging is performed.</param>
        protected SsdpDevicePublisherBase(ISsdpCommunicationsServer communicationsServer, string osName, string osVersion, ISsdpLogger log)
        {
            if (communicationsServer == null)
            {
                throw new ArgumentNullException("communicationsServer");
            }
            if (osName == null)
            {
                throw new ArgumentNullException("osName");
            }
            if (osName.Length == 0)
            {
                throw new ArgumentException("osName cannot be an empty string.", "osName");
            }
            if (osVersion == null)
            {
                throw new ArgumentNullException("osVersion");
            }
            if (osVersion.Length == 0)
            {
                throw new ArgumentException("osVersion cannot be an empty string.", "osName");
            }

            _Log = log ?? NullLogger.Instance;
            _SupportPnpRootDevice = true;
            _Devices              = new List <SsdpRootDevice>();
            _ReadOnlyDevices      = new ReadOnlyEnumerable <SsdpRootDevice>(_Devices);
            _RecentSearchRequests = new Dictionary <string, SearchRequest>(StringComparer.OrdinalIgnoreCase);
            _Random          = new Random();
            _DeviceValidator = new Upnp10DeviceValidator();             //Should probably inject this later, but for now we only support 1.0.

            _CommsServer = communicationsServer;
            _CommsServer.RequestReceived += CommsServer_RequestReceived;
            _OSName    = osName;
            _OSVersion = osVersion;

            _Log.LogInfo("Publisher started.");
            _CommsServer.BeginListeningForBroadcasts();
            _Log.LogInfo("Publisher started listening for broadcasts.");
        }
Exemplo n.º 17
0
        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="communicationsServer">The <see cref="ISsdpCommunicationsServer"/> implementation, used to send and receive SSDP network messages.</param>
        /// <param name="osName">Then name of the operating system running the server.</param>
        /// <param name="osVersion">The version of the operating system running the server.</param>
        protected SsdpDevicePublisherBase(ISsdpCommunicationsServer communicationsServer, string osName, string osVersion)
        {
            if (communicationsServer == null) throw new ArgumentNullException("communicationsServer");
            if (osName == null) throw new ArgumentNullException("osName");
            if (osName.Length == 0) throw new ArgumentException("osName cannot be an empty string.", "osName");
            if (osVersion == null) throw new ArgumentNullException("osVersion");
            if (osVersion.Length == 0) throw new ArgumentException("osVersion cannot be an empty string.", "osName");

            _SupportPnpRootDevice = true;
            _Devices = new List<SsdpRootDevice>();
            _ReadOnlyDevices = new ReadOnlyEnumerable<SsdpRootDevice>(_Devices);
            _RecentSearchRequests = new Dictionary<string, SearchRequest>(StringComparer.OrdinalIgnoreCase);
            _Random = new Random();
            _DeviceValidator = new Upnp10DeviceValidator(); //Should probably inject this later, but for now we only support 1.0.

            _CommsServer = communicationsServer;
            _CommsServer.RequestReceived += CommsServer_RequestReceived;
            _OSName = osName;
            _OSVersion = osVersion;

            _CommsServer.BeginListeningForBroadcasts();
        }
Exemplo n.º 18
0
 public void IsEmptyReadOnlyEnumerableShouldPassForReadOnlyEnumerableDotEmpty()
 {
     ReadOnlyEnumerable <int> .Empty().IsEmptyReadOnlyEnumerable().Should().BeTrue();
 }
Exemplo n.º 19
0
        public void AddToSourceListShouldThrowForEmptySource()
        {
            Action test = () => ReadOnlyEnumerable <int> .Empty().AddToSourceList(1);

            test.ShouldThrow <NotSupportedException>().WithMessage("Collection is read-only.");
        }
Exemplo n.º 20
0
 public void GetOrCreateReadOnlyEnumerableShouldGetForReadOnlyEnumerableSource()
 {
     var enumerable = new ReadOnlyEnumerable<int>();
     var enumerable2 = enumerable.GetOrCreateReadOnlyEnumerable("Integers");
     enumerable2.As<object>().Should().NotBeSameAs(ReadOnlyEnumerable<int>.Empty());
     enumerable2.As<object>().Should().BeSameAs(enumerable);
 }
Exemplo n.º 21
0
 public void ConcatToReadOnlyEnumerableShouldAddForReadOnlyEnumerableSource()
 {
     var enumerable = new ReadOnlyEnumerable<ODataProperty>();
     enumerable.Count().Should().Be(0);
     enumerable.ConcatToReadOnlyEnumerable("Properties", new ODataProperty());
     enumerable.Count().Should().Be(1);
 }
Exemplo n.º 22
0
        public void EmptyOfTShouldAlwaysReturnTheSameInstance()
        {
            ReadOnlyEnumerable <ODataAction> .Empty().As <object>().Should().BeSameAs(ReadOnlyEnumerable <ODataAction> .Empty());

            ReadOnlyEnumerable <ODataAction> .Empty().As <object>().Should().NotBeSameAs(ReadOnlyEnumerable <ODataFunction> .Empty());
        }
Exemplo n.º 23
0
        public void IsEmptyReadOnlyEnumerableShouldPassForReadOnlyEnumerableDotEmpty()
        {
            var result = ReadOnlyEnumerable <int> .Empty().IsEmptyReadOnlyEnumerable();

            Assert.True(result);
        }
Exemplo n.º 24
0
 public void EmptyOfTShouldAlwaysReturnTheSameInstance()
 {
     Assert.Same(ReadOnlyEnumerable <ODataAction> .Empty(), ReadOnlyEnumerable <ODataAction> .Empty());
     Assert.NotSame(ReadOnlyEnumerable <ODataAction> .Empty(), ReadOnlyEnumerable <ODataFunction> .Empty());
 }
        /// <summary>
        /// Reads the content of a properties in an element (complex value, m:properties, ...)
        /// </summary>
        /// <param name="structuredType">The type which should declare the properties to be read. Optional.</param>
        /// <param name="properties">The list of properties to add properties to.</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use.</param>
        /// <remarks>
        /// Pre-Condition:  XmlNodeType.Element    - The element to read properties from.
        /// Post-Condition: XmlNodeType.Element    - The element to read properties from if it is an empty element.
        ///                 XmlNodeType.EndElement - The end element of the element to read properties from.
        /// </remarks>
        private void ReadPropertiesImplementation(IEdmStructuredType structuredType, ReadOnlyEnumerable<ODataProperty> properties, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
        {
            Debug.Assert(properties != null, "properties != null");
            Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null");
            this.AssertXmlCondition(XmlNodeType.Element);

            // Empty values are valid - they have no properties
            if (!this.XmlReader.IsEmptyElement)
            {
                // Read over the complex value element to its first child node (or end-element)
                this.XmlReader.ReadStartElement();

                // WCF DS will skip over the rest of the complex value or entity properties if the first element in it is preceded with
                // a text node. Once the first element is found (no matter its namespace) then the non-element nodes
                // are ignored but skipped and the reading continues.
                // For ODataLib we should not do this and probably just ignore the text node even at the beginning (to be consistent).
                do
                {
                    switch (this.XmlReader.NodeType)
                    {
                        case XmlNodeType.Element:
                            if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataNamespace))
                            {
                                // Found a property
                                IEdmProperty edmProperty = null;
                                bool isOpen = false;
                                bool ignoreProperty = false;

                                if (structuredType != null)
                                {
                                    // Lookup the property in metadata
                                    edmProperty = ReaderValidationUtils.ValidateValuePropertyDefined(this.XmlReader.LocalName, structuredType, this.MessageReaderSettings, out ignoreProperty);
                                    if (edmProperty != null && edmProperty.PropertyKind == EdmPropertyKind.Navigation)
                                    {
                                        throw new ODataException(ODataErrorStrings.ODataAtomPropertyAndValueDeserializer_NavigationPropertyInProperties(edmProperty.Name, structuredType));
                                    }

                                    // If the property was not declared, it must be open.
                                    isOpen = edmProperty == null;
                                }

                                if (ignoreProperty)
                                {
                                    this.XmlReader.Skip();
                                }
                                else
                                {
                                    // EdmLib bridge marks all key properties as non-nullable, but Astoria allows them to be nullable.
                                    // If the property has an annotation to ignore null values, we need to omit the property in requests.
                                    ODataNullValueBehaviorKind nullValueReadBehaviorKind = this.ReadingResponse || edmProperty == null 
                                        ? ODataNullValueBehaviorKind.Default 
                                        : this.Model.NullValueReadBehaviorKind(edmProperty);
                                    ODataProperty property = this.ReadProperty(
                                        false,
                                        edmProperty == null ? null : edmProperty.Name,
                                        edmProperty == null ? null : edmProperty.Type, 
                                        nullValueReadBehaviorKind);
                                    Debug.Assert(
                                        property != null || nullValueReadBehaviorKind == ODataNullValueBehaviorKind.IgnoreValue,
                                        "If we don't ignore null values the property must not be null.");

                                    if (property != null)
                                    {
                                        if (isOpen)
                                        {
                                            ValidationUtils.ValidateOpenPropertyValue(property.Name, property.Value);
                                        }

                                        duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property);
                                        properties.AddToSourceList(property);
                                    }
                                }
                            }
                            else
                            {
                                this.XmlReader.Skip();
                            }

                            break;

                        case XmlNodeType.EndElement:
                            // End of the complex value.
                            break;

                        default:
                            // Non-element so for example a text node, just ignore
                            this.XmlReader.Skip();
                            break;
                    }
                }
                while (this.XmlReader.NodeType != XmlNodeType.EndElement);
            }
        }
        /// <summary>
        /// Read a complex value from the reader.
        /// </summary>
        /// <param name="complexTypeReference">The type reference of the value to read (or null if no type is available).</param>
        /// <param name="payloadTypeName">The name of the type specified in the payload.</param>
        /// <param name="serializationTypeNameAnnotation">The serialization type name for the complex value (possibly null).</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use (cached), or null if new one should be created.</param>
        /// <returns>The value read from the payload.</returns>
        /// <remarks>
        /// Pre-Condition:   XmlNodeType.Element   - the element to read the value for.
        ///                  XmlNodeType.Attribute - an attribute on the element to read the value for.
        /// Post-Condition:  XmlNodeType.EndElement - the element has been read.
        ///                  
        /// Note that this method will not read null values, those should be handled by the caller already.
        /// </remarks>
        private ODataComplexValue ReadComplexValue(
            IEdmComplexTypeReference complexTypeReference, 
            string payloadTypeName, 
            SerializationTypeNameAnnotation serializationTypeNameAnnotation,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
        {
            this.AssertXmlCondition(XmlNodeType.Element, XmlNodeType.Attribute);

            this.IncreaseRecursionDepth();

            ODataComplexValue complexValue = new ODataComplexValue();
            IEdmComplexType complexType = complexTypeReference == null ? null : (IEdmComplexType)complexTypeReference.Definition;

            // If we have a metadata type for the complex value, use that type name
            // otherwise use the type name from the payload (if there was any).
            complexValue.TypeName = complexType == null ? payloadTypeName : complexType.ODataFullName();
            if (serializationTypeNameAnnotation != null)
            {
                complexValue.SetAnnotation(serializationTypeNameAnnotation);
            }

            // Move to the element (so that if we were on an attribute we can test the element for being empty)
            this.XmlReader.MoveToElement();

            if (duplicatePropertyNamesChecker == null)
            {
                duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker();
            }
            else
            {
                duplicatePropertyNamesChecker.Clear();
            }

            ReadOnlyEnumerable<ODataProperty> properties = new ReadOnlyEnumerable<ODataProperty>();
            this.ReadPropertiesImplementation(complexType, properties, duplicatePropertyNamesChecker);
            complexValue.Properties = properties;

            this.AssertXmlCondition(true, XmlNodeType.EndElement);
            Debug.Assert(complexValue != null, "The method should never return null since it doesn't handle null values.");

            this.DecreaseRecursionDepth();

            return complexValue;
        }
 /// <summary>
 /// Reads the content of a properties in an element (complex value, m:properties, ...)
 /// </summary>
 /// <param name="structuredType">The type which should declare the properties to be read. Optional.</param>
 /// <param name="properties">The list of properties to add properties to.</param>
 /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use.</param>
 /// <remarks>
 /// Pre-Condition:  XmlNodeType.Element    - The element to read properties from.
 /// Post-Condition: XmlNodeType.Element    - The element to read properties from if it is an empty element.
 ///                 XmlNodeType.EndElement - The end element of the element to read properties from.
 /// </remarks>
 protected void ReadProperties(IEdmStructuredType structuredType, ReadOnlyEnumerable<ODataProperty> properties, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
 {
     this.AssertRecursionDepthIsZero();
     this.ReadPropertiesImplementation(
         structuredType,
         properties,
         duplicatePropertyNamesChecker);
     this.AssertRecursionDepthIsZero();
 }
        /// <summary>
        /// Reads the content of a properties in an element (complex value, m:properties, ...)
        /// </summary>
        /// <param name="structuredType">The type which should declare the properties to be read. Optional.</param>
        /// <param name="properties">The list of properties to add properties to.</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use.</param>
        /// <remarks>
        /// Pre-Condition:  XmlNodeType.Element    - The element to read properties from.
        /// Post-Condition: XmlNodeType.Element    - The element to read properties from if it is an empty element.
        ///                 XmlNodeType.EndElement - The end element of the element to read properties from.
        /// </remarks>
        private void ReadPropertiesImplementation(IEdmStructuredType structuredType, ReadOnlyEnumerable <ODataProperty> properties, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
        {
            Debug.Assert(properties != null, "properties != null");
            Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null");
            this.AssertXmlCondition(XmlNodeType.Element);

            // Empty values are valid - they have no properties
            if (!this.XmlReader.IsEmptyElement)
            {
                // Read over the complex value element to its first child node (or end-element)
                this.XmlReader.ReadStartElement();

                // WCF DS will skip over the rest of the complex value or entity properties if the first element in it is preceded with
                // a text node. Once the first element is found (no matter its namespace) then the non-element nodes
                // are ignored but skipped and the reading continues.
                // For ODataLib we should not do this and probably just ignore the text node even at the beginning (to be consistent).
                do
                {
                    switch (this.XmlReader.NodeType)
                    {
                    case XmlNodeType.Element:
                        if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataNamespace))
                        {
                            // Found a property
                            IEdmProperty edmProperty    = null;
                            bool         isOpen         = false;
                            bool         ignoreProperty = false;

                            if (structuredType != null)
                            {
                                // Lookup the property in metadata
                                edmProperty = ReaderValidationUtils.ValidateValuePropertyDefined(this.XmlReader.LocalName, structuredType, this.MessageReaderSettings, out ignoreProperty);
                                if (edmProperty != null && edmProperty.PropertyKind == EdmPropertyKind.Navigation)
                                {
                                    throw new ODataException(ODataErrorStrings.ODataAtomPropertyAndValueDeserializer_NavigationPropertyInProperties(edmProperty.Name, structuredType));
                                }

                                // If the property was not declared, it must be open.
                                isOpen = edmProperty == null;
                            }

                            if (ignoreProperty)
                            {
                                this.XmlReader.Skip();
                            }
                            else
                            {
                                // EdmLib bridge marks all key properties as non-nullable, but Astoria allows them to be nullable.
                                // If the property has an annotation to ignore null values, we need to omit the property in requests.
                                ODataNullValueBehaviorKind nullValueReadBehaviorKind = this.ReadingResponse || edmProperty == null
                                        ? ODataNullValueBehaviorKind.Default
                                        : this.Model.NullValueReadBehaviorKind(edmProperty);
                                ODataProperty property = this.ReadProperty(
                                    false,
                                    edmProperty == null ? null : edmProperty.Name,
                                    edmProperty == null ? null : edmProperty.Type,
                                    nullValueReadBehaviorKind);
                                Debug.Assert(
                                    property != null || nullValueReadBehaviorKind == ODataNullValueBehaviorKind.IgnoreValue,
                                    "If we don't ignore null values the property must not be null.");

                                if (property != null)
                                {
                                    if (isOpen)
                                    {
                                        ValidationUtils.ValidateOpenPropertyValue(property.Name, property.Value);
                                    }

                                    duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property);
                                    properties.AddToSourceList(property);
                                }
                            }
                        }
                        else
                        {
                            this.XmlReader.Skip();
                        }

                        break;

                    case XmlNodeType.EndElement:
                        // End of the complex value.
                        break;

                    default:
                        // Non-element so for example a text node, just ignore
                        this.XmlReader.Skip();
                        break;
                    }
                }while (this.XmlReader.NodeType != XmlNodeType.EndElement);
            }
        }
Exemplo n.º 29
0
        public void ToReadOnlyEnumerableShouldNotThrowForReadOnlyEnumerableSource()
        {
            var result = new ReadOnlyEnumerable <int>().ToReadOnlyEnumerable("Integers");

            Assert.Empty(result);
        }
Exemplo n.º 30
0
        private void SetEpmValueForSegment(
            EntityPropertyMappingInfo epmInfo,
            int propertyValuePathIndex,
            IEdmStructuredTypeReference segmentStructuralTypeReference,
            ReadOnlyEnumerable <ODataProperty> existingProperties,
            object propertyValue)
        {
            Debug.Assert(epmInfo != null, "epmInfo != null");
            Debug.Assert(propertyValuePathIndex < epmInfo.PropertyValuePath.Length, "The propertyValuePathIndex is out of bounds.");
            Debug.Assert(existingProperties != null, "existingProperties != null");

            string propertyName = epmInfo.PropertyValuePath[propertyValuePathIndex].PropertyName;

            // Do not set out-of-content values if the EPM is defined as KeepInContent=true.
            if (epmInfo.Attribute.KeepInContent)
            {
                return;
            }

            // Try to find the property in the existing properties
            // If the property value is atomic from point of view of EPM (non-streaming collection or primitive) then if it already exists
            // it must have been in-content, and thus we leave it as is (note that two EPMs can't map to the same property, we verify that upfront).
            // If the property value is non-atomic, then it is a complex value, we might want to merge the new value comming from EPM with it.
            ODataProperty     existingProperty     = existingProperties.FirstOrDefault(p => string.CompareOrdinal(p.Name, propertyName) == 0);
            ODataComplexValue existingComplexValue = null;

            if (existingProperty != null)
            {
                // In case the property exists and it's a complex value we will try to merge.
                // Note that if the property is supposed to be complex, but it already has a null value, then the null wins.
                // Since in-content null complex value wins over any EPM complex value.
                existingComplexValue = existingProperty.Value as ODataComplexValue;
                if (existingComplexValue == null)
                {
                    return;
                }
            }

            IEdmProperty propertyMetadata = segmentStructuralTypeReference.FindProperty(propertyName);

            Debug.Assert(propertyMetadata != null || segmentStructuralTypeReference.IsOpen(), "We should have verified that if the property is not declared the type must be open.");

            // TODO: Server seems to have a bug where if there's an EPM for an open property where the EPM uses complex types (the source path is deeper than 1)
            // then it will actually materialize the property as entry level string property, with the value of the deep property value. If there are multiple deep
            // EPM for the same top-level open property it seems to set the entry level property multiple times with the values as they come from payload.
            // Client on the other hand doesn't have open properties, and always has a type, so no problem there.
            if (propertyMetadata == null && propertyValuePathIndex != epmInfo.PropertyValuePath.Length - 1)
            {
                throw new ODataException(ODataErrorStrings.EpmReader_OpenComplexOrCollectionEpmProperty(epmInfo.Attribute.SourcePath));
            }

            // Open properties in EPM are by default of type Edm.String - there's no way to specify a typename in EPM
            // consumer is free to do the conversion later on if it needs to.
            // Note that this effectively means that ODataMessageReaderSettings.DisablePrimitiveTypeConversion is as if it's turned on for open EPM properties.
            IEdmTypeReference propertyType;

            if (propertyMetadata == null ||
                (this.MessageReaderSettings.DisablePrimitiveTypeConversion && propertyMetadata.Type.IsODataPrimitiveTypeKind()))
            {
                propertyType = EdmCoreModel.Instance.GetString(/*nullable*/ true);
            }
            else
            {
                propertyType = propertyMetadata.Type;
            }

            // NOTE: WCF DS Server only applies the values when
            // - It's an open property
            // - It's not a key property
            // - It's a key property and it's a POST operation
            // ODataLib here will always set the property though.
            switch (propertyType.TypeKind())
            {
            case EdmTypeKind.Primitive:
            {
                if (propertyType.IsStream())
                {
                    throw new ODataException(ODataErrorStrings.General_InternalError(InternalErrorCodes.EpmReader_SetEpmValueForSegment_StreamProperty));
                }

                object primitiveValue;
                if (propertyValue == null)
                {
                    ReaderValidationUtils.ValidateNullValue(
                        this.atomInputContext.Model,
                        propertyType,
                        this.atomInputContext.MessageReaderSettings,
                        /*validateNullValue*/ true,
                        this.atomInputContext.Version,
                        propertyName);

                    primitiveValue = null;
                }
                else
                {
                    // Convert the value to the desired target type
                    primitiveValue = AtomValueUtils.ConvertStringToPrimitive((string)propertyValue, propertyType.AsPrimitive());
                }

                this.AddEpmPropertyValue(existingProperties, propertyName, primitiveValue, segmentStructuralTypeReference.IsODataEntityTypeKind());
            }

            break;

            case EdmTypeKind.Complex:
                // Note: Unlike WCF DS we don't have a preexisting instance to override (since complex values are atomic, so we should not updated them)
                // In our case the complex value either doesn't exist yet on the entry being reported (easy, create it)
                // or it exists, but then it was created during reading of previous normal or EPM properties for this entry. It never exists before
                // we ever get to see the entity. So in our case we will never recreate the complex value, we always start with new one
                // and update it with new properties as they come. (Next time we will start over with a new complex value.)
                Debug.Assert(
                    existingComplexValue == null || (existingProperty != null && existingProperty.Value == existingComplexValue),
                    "If we have existing complex value, we must have an existing property as well.");
                Debug.Assert(
                    epmInfo.PropertyValuePath.Length > propertyValuePathIndex + 1,
                    "Complex value can not be a leaf segment in the source property path. We should have failed constructing the EPM trees for it.");

                if (existingComplexValue == null)
                {
                    Debug.Assert(existingProperty == null, "If we don't have an existing complex value, then we must not have an existing property at all.");

                    // Create a new complex value and set its type name to the type name of the property type (in case of EPM we never have type name from the payload)
                    existingComplexValue = new ODataComplexValue
                    {
                        TypeName   = propertyType.ODataFullName(),
                        Properties = new ReadOnlyEnumerable <ODataProperty>()
                    };

                    this.AddEpmPropertyValue(existingProperties, propertyName, existingComplexValue, segmentStructuralTypeReference.IsODataEntityTypeKind());
                }

                // Get the properties list of the complex value and recursively set the next EPM segment value to it.
                // Note that on inner complex value we don't need to check for duplicate properties
                // because EPM will never add a property which already exists (see the start of this method).
                IEdmComplexTypeReference complexPropertyTypeReference = propertyType.AsComplex();
                Debug.Assert(complexPropertyTypeReference != null, "complexPropertyTypeReference != null");
                this.SetEpmValueForSegment(
                    epmInfo,
                    propertyValuePathIndex + 1,
                    complexPropertyTypeReference,
                    existingComplexValue.Properties.ToReadOnlyEnumerable("Properties"),
                    propertyValue);

                break;

            case EdmTypeKind.Collection:
                Debug.Assert(propertyType.IsNonEntityCollectionType(), "Collection types in EPM must be atomic.");

                // In this case the property value is the internal list of items.
                // Create a new collection value and set the list as the list of items on it.
                ODataCollectionValue collectionValue = new ODataCollectionValue
                {
                    TypeName = propertyType.ODataFullName(),
                    Items    = new ReadOnlyEnumerable((List <object>)propertyValue)
                };

                this.AddEpmPropertyValue(existingProperties, propertyName, collectionValue, segmentStructuralTypeReference.IsODataEntityTypeKind());

                break;

            default:
                throw new ODataException(ODataErrorStrings.General_InternalError(InternalErrorCodes.EpmReader_SetEpmValueForSegment_TypeKind));
            }
        }
        /// <summary>
        /// Reads the content of a properties in an element (complex value, m:properties, ...)
        /// </summary>
        /// <param name="structuredType">The type which should declare the properties to be read. Optional.</param>
        /// <param name="properties">The list of properties to add properties to.</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use.</param>
        /// <param name="epmPresent">Whether any EPM mappings exist.</param>
        /// <remarks>
        /// Pre-Condition:  XmlNodeType.Element    - The element to read properties from.
        /// Post-Condition: XmlNodeType.Element    - The element to read properties from if it is an empty element.
        ///                 XmlNodeType.EndElement - The end element of the element to read properties from.
        /// </remarks>
        private void ReadPropertiesImplementation(IEdmStructuredType structuredType, ReadOnlyEnumerable <ODataProperty> properties, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, bool epmPresent)
        {
            Debug.Assert(properties != null, "properties != null");
            Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null");
            this.AssertXmlCondition(XmlNodeType.Element);

            // Empty values are valid - they have no properties
            if (!this.XmlReader.IsEmptyElement)
            {
                // Read over the complex value element to its first child node (or end-element)
                this.XmlReader.ReadStartElement();

                do
                {
                    switch (this.XmlReader.NodeType)
                    {
                    case XmlNodeType.Element:
                        if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataNamespace))
                        {
                            // Found a property
                            IEdmProperty edmProperty    = null;
                            bool         isOpen         = false;
                            bool         ignoreProperty = false;

                            if (structuredType != null)
                            {
                                // Lookup the property in metadata
                                edmProperty = ReaderValidationUtils.ValidateValuePropertyDefined(this.XmlReader.LocalName, structuredType, this.MessageReaderSettings, out ignoreProperty);
                                if (edmProperty != null && edmProperty.PropertyKind == EdmPropertyKind.Navigation)
                                {
                                    throw new ODataException(ODataErrorStrings.ODataAtomPropertyAndValueDeserializer_NavigationPropertyInProperties(edmProperty.Name, structuredType));
                                }

                                // If the property was not declared, it must be open.
                                isOpen = edmProperty == null;
                            }

                            if (ignoreProperty)
                            {
                                this.XmlReader.Skip();
                            }
                            else
                            {
                                ODataNullValueBehaviorKind nullValueReadBehaviorKind = this.ReadingResponse || edmProperty == null
                                        ? ODataNullValueBehaviorKind.Default
                                        : this.Model.NullValueReadBehaviorKind(edmProperty);
                                ODataProperty property = this.ReadProperty(
                                    edmProperty == null ? null : edmProperty.Name,
                                    edmProperty == null ? null : edmProperty.Type,
                                    nullValueReadBehaviorKind,
                                    epmPresent);
                                Debug.Assert(
                                    property != null || nullValueReadBehaviorKind == ODataNullValueBehaviorKind.IgnoreValue,
                                    "If we don't ignore null values the property must not be null.");

                                if (property != null)
                                {
                                    if (isOpen)
                                    {
                                        ValidationUtils.ValidateOpenPropertyValue(property.Name, property.Value, this.MessageReaderSettings.UndeclaredPropertyBehaviorKinds);
                                    }

                                    duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property);
                                    properties.AddToSourceList(property);
                                }
                            }
                        }
                        else
                        {
                            this.XmlReader.Skip();
                        }

                        break;

                    case XmlNodeType.EndElement:
                        // End of the complex value.
                        break;

                    default:
                        // Non-element so for example a text node, just ignore
                        this.XmlReader.Skip();
                        break;
                    }
                }while (this.XmlReader.NodeType != XmlNodeType.EndElement);
            }
        }