public void WriteInstanceAnnotation_ForCollectionShouldUseCollectionCodePath()
        {
            var collectionValue = new ODataCollectionValue()
            {
                TypeName = "Collection(String)"
            };

            collectionValue.SetAnnotation(new SerializationTypeNameAnnotation()
            {
                TypeName = null
            });
            const string term          = "some.term";
            var          verifierCalls = 0;

            this.jsonWriter.WriteNameVerifier = (name) =>
            {
                name.Should().Be("@" + term);
                verifierCalls++;
            };
            this.valueWriter.WriteCollectionVerifier = (value, reference, valueTypeReference, isTopLevelProperty, isInUri, isOpenProperty) =>
            {
                value.Should().Be(collectionValue);
                reference.Should().BeNull();
                valueTypeReference.Should().NotBeNull();
                valueTypeReference.IsCollection().Should().BeTrue();
                valueTypeReference.AsCollection().ElementType().IsString().Should().BeTrue();
                isOpenProperty.Should().BeTrue();
                isTopLevelProperty.Should().BeFalse();
                isInUri.Should().BeFalse();
                verifierCalls.Should().Be(1);
                verifierCalls++;
            };
            this.jsonLightInstanceAnnotationWriter.WriteInstanceAnnotation(new ODataInstanceAnnotation(term, collectionValue));
            verifierCalls.Should().Be(2);
        }
Пример #2
0
        /// <summary>
        /// Adds the type name annotations required for proper json light serialization.
        /// </summary>
        /// <param name="value">The collection value for which the annotations have to be added.</param>
        /// <param name="metadataLevel">The OData metadata level of the response.</param>
        protected internal static void AddTypeNameAnnotationAsNeeded(ODataCollectionValue value, ODataMetadataLevel metadataLevel)
        {
            // ODataLib normally has the caller decide whether or not to serialize properties by leaving properties
            // null when values should not be serialized. The TypeName property is different and should always be
            // provided to ODataLib to enable model validation. A separate annotation is used to decide whether or not
            // to serialize the type name (a null value prevents serialization).

            Contract.Assert(value != null);

            // Only add an annotation if we want to override ODataLib's default type name serialization behavior.
            if (ShouldAddTypeNameAnnotation(metadataLevel))
            {
                string typeName;

                // Provide the type name to serialize (or null to force it not to serialize).
                if (ShouldSuppressTypeNameSerialization(metadataLevel))
                {
                    typeName = null;
                }
                else
                {
                    typeName = value.TypeName;
                }

                value.SetAnnotation <SerializationTypeNameAnnotation>(new SerializationTypeNameAnnotation
                {
                    TypeName = typeName
                });
            }
        }
Пример #3
0
        private ODataCollectionValue ReadCollectionValue(IEdmCollectionTypeReference collectionTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation)
        {
            this.IncreaseRecursionDepth();
            ODataCollectionValue value2 = new ODataCollectionValue {
                TypeName = (collectionTypeReference == null) ? payloadTypeName : collectionTypeReference.ODataFullName()
            };

            if (serializationTypeNameAnnotation != null)
            {
                value2.SetAnnotation <SerializationTypeNameAnnotation>(serializationTypeNameAnnotation);
            }
            base.XmlReader.MoveToElement();
            List <object> sourceEnumerable = new List <object>();

            if (!base.XmlReader.IsEmptyElement)
            {
                base.XmlReader.ReadStartElement();
                IEdmTypeReference                      expectedTypeReference         = (collectionTypeReference == null) ? null : collectionTypeReference.ElementType();
                DuplicatePropertyNamesChecker          duplicatePropertyNamesChecker = base.CreateDuplicatePropertyNamesChecker();
                CollectionWithoutExpectedTypeValidator collectionValidator           = null;
                if (collectionTypeReference == null)
                {
                    string itemTypeNameFromCollection = (payloadTypeName == null) ? null : EdmLibraryExtensions.GetCollectionItemTypeName(payloadTypeName);
                    collectionValidator = new CollectionWithoutExpectedTypeValidator(itemTypeNameFromCollection);
                }
                do
                {
                    switch (base.XmlReader.NodeType)
                    {
                    case XmlNodeType.Element:
                        if (base.XmlReader.NamespaceEquals(base.XmlReader.ODataNamespace))
                        {
                            if (!base.XmlReader.LocalNameEquals(this.ODataCollectionItemElementName))
                            {
                                throw new ODataException(Microsoft.Data.OData.Strings.ODataAtomPropertyAndValueDeserializer_InvalidCollectionElement(base.XmlReader.LocalName, base.XmlReader.ODataNamespace));
                            }
                            object item = this.ReadNonEntityValueImplementation(expectedTypeReference, duplicatePropertyNamesChecker, collectionValidator, true, false);
                            base.XmlReader.Read();
                            ValidationUtils.ValidateCollectionItem(item, false);
                            sourceEnumerable.Add(item);
                        }
                        else
                        {
                            base.XmlReader.Skip();
                        }
                        break;

                    case XmlNodeType.EndElement:
                        break;

                    default:
                        base.XmlReader.Skip();
                        break;
                    }
                }while (base.XmlReader.NodeType != XmlNodeType.EndElement);
            }
            value2.Items = new ReadOnlyEnumerable(sourceEnumerable);
            this.DecreaseRecursionDepth();
            return(value2);
        }
Пример #4
0
        public void BuildPropertyContextUriForCollectionPropertyValueWithNonNullAnnotation()
        {
            ODataCollectionValue value = new ODataCollectionValue {
                TypeName = "FQNS.FromObject"
            };

            value.SetAnnotation(new SerializationTypeNameAnnotation {
                TypeName = "FQNS.FromAnnotation"
            });
            var contextUri = this.CreatePropertyContextUri(value);

            contextUri.OriginalString.Should().Be(BuildExpectedContextUri("#FQNS.FromAnnotation"));
        }
Пример #5
0
        private ODataCollectionValue CreateODataCollection(Type collectionItemType, string propertyName, object value, List <object> visitedComplexTypeObjects)
        {
            PrimitiveType                    type;
            string                           edmType;
            Func <object, object>            valueConverter = null;
            Func <object, ODataComplexValue> func2          = null;

            WebUtil.ValidateCollection(collectionItemType, value, propertyName);
            bool flag = PrimitiveType.TryGetPrimitiveType(collectionItemType, out type);
            ODataCollectionValue value2     = new ODataCollectionValue();
            IEnumerable          enumerable = (IEnumerable)value;

            if (flag)
            {
                edmType = ClientConvert.GetEdmType(Nullable.GetUnderlyingType(collectionItemType) ?? collectionItemType);
                if (valueConverter == null)
                {
                    valueConverter = delegate(object val) {
                        WebUtil.ValidateCollectionItem(val);
                        WebUtil.ValidatePrimitiveCollectionItem(val, propertyName, collectionItemType);
                        return(GetPrimitiveValue(val, collectionItemType));
                    };
                }
                value2.Items = Util.GetEnumerable <object>(enumerable, valueConverter);
            }
            else
            {
                edmType = this.requestInfo.ResolveNameFromType(collectionItemType);
                if (func2 == null)
                {
                    func2 = delegate(object val) {
                        WebUtil.ValidateCollectionItem(val);
                        WebUtil.ValidateComplexCollectionItem(val, propertyName, collectionItemType);
                        return(this.CreateODataComplexValue(collectionItemType, val, propertyName, true, visitedComplexTypeObjects));
                    };
                }
                value2.Items = Util.GetEnumerable <ODataComplexValue>(enumerable, func2);
            }
            string str2 = (edmType == null) ? null : string.Format(CultureInfo.InvariantCulture, "Collection({0})", new object[] { edmType });
            SerializationTypeNameAnnotation annotation = new SerializationTypeNameAnnotation {
                TypeName = str2
            };

            value2.SetAnnotation <SerializationTypeNameAnnotation>(annotation);
            return(value2);
        }
Пример #6
0
        public void TypeNameShouldComeFromSerializationTypeNameAnnotationForCollectionValue()
        {
            var stna = new SerializationTypeNameAnnotation()
            {
                TypeName = "FromSTNA"
            };
            var value = new ODataCollectionValue()
            {
                TypeName = "Collection(Edm.String)"
            };

            value.SetAnnotation(stna);
            this.typeNameOracle.GetValueTypeNameForWriting(value,
                                                           EdmCoreModel.GetCollection(EdmCoreModel.Instance.GetString(true)),
                                                           EdmCoreModel.GetCollection(EdmCoreModel.Instance.GetString(false)),
                                                           /* isOpenProperty*/ false).Should().Be("FromSTNA");
        }
Пример #7
0
        /// <summary>
        /// Read a collection from the reader.
        /// </summary>
        /// <param name="collectionTypeReference">The type of the collection to read (or null if no type is available).</param>
        /// <param name="payloadTypeName">The name of the collection type specified in the payload.</param>
        /// <param name="serializationTypeNameAnnotation">The serialization type name for the collection value (possibly null).</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.Element    - the element was empty.
        ///                  XmlNodeType.EndElement - the element had some value.
        ///
        /// Note that this method will not read null values, those should be handled by the caller already.
        /// </remarks>
        private ODataCollectionValue ReadCollectionValue(
            IEdmCollectionTypeReference collectionTypeReference,
            string payloadTypeName,
            SerializationTypeNameAnnotation serializationTypeNameAnnotation)
        {
            this.AssertXmlCondition(XmlNodeType.Element, XmlNodeType.Attribute);
            Debug.Assert(
                collectionTypeReference == null || collectionTypeReference.IsNonEntityODataCollectionTypeKind(),
                "If the metadata is specified it must denote a collection for this method to work.");

            this.IncreaseRecursionDepth();

            ODataCollectionValue collectionValue = new ODataCollectionValue();

            // If we have a metadata type for the collection, use that type name
            // otherwise use the type name from the payload (if there was any).
            collectionValue.TypeName = collectionTypeReference == null ? payloadTypeName : collectionTypeReference.ODataFullName();
            if (serializationTypeNameAnnotation != null)
            {
                collectionValue.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();

            List <object> items = new List <object>();

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

                IEdmTypeReference itemTypeReference = collectionTypeReference == null ? null : collectionTypeReference.ElementType();

                DuplicatePropertyNamesChecker          duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker();
                CollectionWithoutExpectedTypeValidator collectionValidator           = null;
                if (collectionTypeReference == null)
                {
                    // Parse the type name from the payload (if any), extract the item type name and construct a collection validator
                    string itemTypeName = payloadTypeName == null ? null : EdmLibraryExtensions.GetCollectionItemTypeName(payloadTypeName);
                    collectionValidator = new CollectionWithoutExpectedTypeValidator(itemTypeName);
                }

                do
                {
                    switch (this.XmlReader.NodeType)
                    {
                    case XmlNodeType.Element:
                        if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataNamespace))
                        {
                            if (!this.XmlReader.LocalNameEquals(this.ODataCollectionItemElementName))
                            {
                                throw new ODataException(o.Strings.ODataAtomPropertyAndValueDeserializer_InvalidCollectionElement(this.XmlReader.LocalName, this.XmlReader.ODataNamespace));
                            }

                            // We don't support EPM for collections so it is fine to say that EPM is not present
                            object itemValue = this.ReadNonEntityValueImplementation(
                                itemTypeReference,
                                duplicatePropertyNamesChecker,
                                collectionValidator,
                                /*validateNullValue*/ true,
                                /*epmPresent*/ false);

                            // read over the end tag of the element or the start tag if the element was empty.
                            this.XmlReader.Read();

                            // Validate the item (for example that it's not null)
                            ValidationUtils.ValidateCollectionItem(itemValue, false /* isStreamable */);

                            // Note that the ReadNonEntityValue already validated that the actual type of the value matches
                            // the expected type (the itemType).
                            items.Add(itemValue);
                        }
                        else
                        {
                            this.XmlReader.Skip();
                        }

                        break;

                    case XmlNodeType.EndElement:
                        // End of the collection.
                        break;

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

            collectionValue.Items = new ReadOnlyEnumerable(items);

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

            this.DecreaseRecursionDepth();

            return(collectionValue);
        }
        /// <summary>
        /// Read a collection from the reader.
        /// </summary>
        /// <param name="collectionTypeReference">The type of the collection to read (or null if no type is available).</param>
        /// <param name="payloadTypeName">The name of the collection type specified in the payload.</param>
        /// <param name="serializationTypeNameAnnotation">The serialization type name for the collection value (possibly null).</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.Element    - the element was empty.
        ///                  XmlNodeType.EndElement - the element had some value.
        ///                  
        /// Note that this method will not read null values, those should be handled by the caller already.
        /// </remarks>
        private ODataCollectionValue ReadCollectionValue(
            IEdmCollectionTypeReference collectionTypeReference, 
            string payloadTypeName,
            SerializationTypeNameAnnotation serializationTypeNameAnnotation)
        {
            this.AssertXmlCondition(XmlNodeType.Element, XmlNodeType.Attribute);
            Debug.Assert(
                collectionTypeReference == null || collectionTypeReference.IsNonEntityCollectionType(),
                "If the metadata is specified it must denote a collection for this method to work.");

            this.IncreaseRecursionDepth();

            ODataCollectionValue collectionValue = new ODataCollectionValue();

            // If we have a metadata type for the collection, use that type name
            // otherwise use the type name from the payload (if there was any).
            collectionValue.TypeName = collectionTypeReference == null ? payloadTypeName : collectionTypeReference.ODataFullName();
            if (serializationTypeNameAnnotation != null)
            {
                collectionValue.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();

            List<object> items = new List<object>();

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

                // If we don't have metadata (that is collectionType is null) we parse the type name
                // and extract the item type name from it. Then we create a CollectionWithoutExpectedTypeValidator
                // instance and use it to ensure that all item types read for the collection value are consistent with
                // the item type derived from the collection value's type name.
                // Note that if an item does not specify a type name but the collection value does, the item will be
                // assigned the item type name computed from the collection value's type.
                // Note that JSON doesn't have this problem since in JSON we always have metadata and thus the collectionType
                // is never null by the time we get to a similar place in the code.
                IEdmTypeReference itemTypeReference = collectionTypeReference == null ? null : collectionTypeReference.ElementType();

                DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker();
                CollectionWithoutExpectedTypeValidator collectionValidator = null;
                if (collectionTypeReference == null)
                {
                    // Parse the type name from the payload (if any), extract the item type name and construct a collection validator
                    string itemTypeName = payloadTypeName == null ? null : EdmLibraryExtensions.GetCollectionItemTypeName(payloadTypeName);
                    collectionValidator = new CollectionWithoutExpectedTypeValidator(itemTypeName);
                }

                do
                {
                    switch (this.XmlReader.NodeType)
                    {
                        case XmlNodeType.Element:
                            if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataMetadataNamespace))
                            {
                                if (!this.XmlReader.LocalNameEquals(this.ODataCollectionItemElementName))
                                {
                                    this.XmlReader.Skip();
                                }
                                else
                                {
                                    object itemValue = this.ReadNonEntityValueImplementation(
                                        itemTypeReference,
                                        duplicatePropertyNamesChecker,
                                        collectionValidator,
                                        /*validateNullValue*/ true,
                                        /*propertyName*/ null);

                                    // read over the end tag of the element or the start tag if the element was empty.
                                    this.XmlReader.Read();

                                    // Validate the item (for example that it's not null)
                                    ValidationUtils.ValidateCollectionItem(itemValue, itemTypeReference.IsNullable());

                                    // Note that the ReadNonEntityValue already validated that the actual type of the value matches
                                    // the expected type (the itemType).
                                    items.Add(itemValue);
                                }
                            }
                            else if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataNamespace))
                            {
                                throw new ODataException(ODataErrorStrings.ODataAtomPropertyAndValueDeserializer_InvalidCollectionElement(this.XmlReader.LocalName, this.XmlReader.ODataMetadataNamespace));  
                            }
                            else
                            {
                                this.XmlReader.Skip();
                            }

                            break;

                        case XmlNodeType.EndElement:
                            // End of the collection.
                            break;

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

            collectionValue.Items = new ReadOnlyEnumerable(items);

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

            this.DecreaseRecursionDepth();

            return collectionValue;
        }
Пример #9
0
        /// <summary>
        /// Reads a collection value.
        /// </summary>
        /// <param name="collectionValueTypeReference">The collection type reference of the value.</param>
        /// <param name="payloadTypeName">The type name read from the payload.</param>
        /// <param name="serializationTypeNameAnnotation">The serialization type name for the collection value (possibly null).</param>
        /// <returns>The value of the collection.</returns>
        /// <remarks>
        /// Pre-Condition:  Fails if the current node is not a JsonNodeType.StartObject
        /// Post-Condition: almost anything - the node after the collection value (after the EndObject)
        /// </remarks>
        private ODataCollectionValue ReadCollectionValueImplementation(
            IEdmCollectionTypeReference collectionValueTypeReference,
            string payloadTypeName,
            SerializationTypeNameAnnotation serializationTypeNameAnnotation)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(
                collectionValueTypeReference == null || collectionValueTypeReference.IsNonEntityCollectionType(),
                "If the metadata is specified it must denote a Collection for this method to work.");
            this.JsonReader.AssertNotBuffering();

            ODataVersionChecker.CheckCollectionValue(this.Version);

            this.IncreaseRecursionDepth();

            // Read over the start object
            this.JsonReader.ReadStartObject();

            ODataCollectionValue collectionValue = new ODataCollectionValue();

            collectionValue.TypeName = collectionValueTypeReference != null?collectionValueTypeReference.ODataFullName() : payloadTypeName;

            if (serializationTypeNameAnnotation != null)
            {
                collectionValue.SetAnnotation(serializationTypeNameAnnotation);
            }

            List <object> items = null;
            bool          metadataPropertyFound = false;

            while (this.JsonReader.NodeType == JsonNodeType.Property)
            {
                string propertyName = this.JsonReader.ReadPropertyName();

                if (string.CompareOrdinal(JsonConstants.ODataMetadataName, propertyName) == 0)
                {
                    // __metadata property
                    if (metadataPropertyFound)
                    {
                        throw new ODataException(ODataErrorStrings.ODataJsonPropertyAndValueDeserializer_MultiplePropertiesInCollectionWrapper(JsonConstants.ODataMetadataName));
                    }

                    metadataPropertyFound = true;

                    // Note that we don't need to read the type name again, as we've already read it above in FindTypeNameInPayload.
                    // There's nothing else of interest in the __metadata for collections.
                    this.JsonReader.SkipValue();
                }
                else if (string.CompareOrdinal(JsonConstants.ODataResultsName, propertyName) == 0)
                {
                    // results property
                    if (items != null)
                    {
                        throw new ODataException(ODataErrorStrings.ODataJsonPropertyAndValueDeserializer_MultiplePropertiesInCollectionWrapper(JsonConstants.ODataResultsName));
                    }

                    items = new List <object>();

                    this.JsonReader.ReadStartArray();

                    DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker();
                    IEdmTypeReference             itemType = null;
                    if (collectionValueTypeReference != null)
                    {
                        itemType = collectionValueTypeReference.CollectionDefinition().ElementType;
                    }

                    // NOTE: we do not support reading Verbose JSON without metadata right now so we always have an expected item type;
                    //       The collection validator is always null.
                    CollectionWithoutExpectedTypeValidator collectionValidator = null;

                    while (this.JsonReader.NodeType != JsonNodeType.EndArray)
                    {
                        object itemValue = this.ReadNonEntityValueImplementation(
                            itemType,
                            duplicatePropertyNamesChecker,
                            collectionValidator,
                            /*validateNullValue*/ true,
                            /*propertyName*/ null);

                        // Validate the item (for example that it's not null)
                        ValidationUtils.ValidateCollectionItem(itemValue, false /* isStreamable */);

                        // Note that the ReadNonEntityValue already validated that the actual type of the value matches
                        // the expected type (the itemType).
                        items.Add(itemValue);
                    }

                    Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndArray, "The results value must end with an end array.");
                    this.JsonReader.ReadEndArray();
                }
                else
                {
                    // Skip over any other property in the collection object
                    this.JsonReader.SkipValue();
                }
            }

            Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndObject, "After all properties of Collection wrapper are read the EndObject node is expected.");
            this.JsonReader.ReadEndObject();

            if (items == null)
            {
                // We didn't find any results property. All collections must have the results property.
                throw new ODataException(ODataErrorStrings.ODataJsonPropertyAndValueDeserializer_CollectionWithoutResults);
            }

            collectionValue.Items = new ReadOnlyEnumerable(items);

            this.JsonReader.AssertNotBuffering();
            this.DecreaseRecursionDepth();

            return(collectionValue);
        }
        /// <summary>
        /// Reads a collection value.
        /// </summary>
        /// <param name="collectionValueTypeReference">The collection type reference of the value.</param>
        /// <param name="payloadTypeName">The type name read from the payload.</param>
        /// <param name="serializationTypeNameAnnotation">The serialization type name for the collection value (possibly null).</param>
        /// <returns>The value of the collection.</returns>
        /// <remarks>
        /// Pre-Condition:  Fails if the current node is not a JsonNodeType.StartArray
        /// Post-Condition: almost anything - the node after the collection value (after the EndArray)
        /// </remarks>
        private ODataCollectionValue ReadCollectionValue(
            IEdmCollectionTypeReference collectionValueTypeReference,
            string payloadTypeName,
            SerializationTypeNameAnnotation serializationTypeNameAnnotation)
        {
            Debug.Assert(
                collectionValueTypeReference == null || collectionValueTypeReference.IsNonEntityCollectionType(),
                "If the metadata is specified it must denote a Collection for this method to work.");

            this.IncreaseRecursionDepth();

            // Read over the start array
            this.JsonReader.ReadStartArray();

            ODataCollectionValue collectionValue = new ODataCollectionValue();
            collectionValue.TypeName = collectionValueTypeReference != null ? collectionValueTypeReference.FullName() : payloadTypeName;
            if (serializationTypeNameAnnotation != null)
            {
                collectionValue.SetAnnotation(serializationTypeNameAnnotation);
            }

            if (collectionValueTypeReference != null)
            {
                collectionValue.SetAnnotation(new ODataTypeAnnotation(collectionValueTypeReference));
            }

            List<object> items = new List<object>();
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker();
            IEdmTypeReference itemType = null;
            if (collectionValueTypeReference != null)
            {
                itemType = collectionValueTypeReference.CollectionDefinition().ElementType;
            }

            // NOTE: we do not support reading JSON Light without metadata right now so we always have an expected item type;
            //       The collection validator is always null.
            CollectionWithoutExpectedTypeValidator collectionValidator = null;

            while (this.JsonReader.NodeType != JsonNodeType.EndArray)
            {
                object itemValue = this.ReadNonEntityValueImplementation(
                    /*payloadTypeName*/ null,
                    itemType,
                    duplicatePropertyNamesChecker,
                    collectionValidator,
                    /*validateNullValue*/ true,
                    /*isTopLevelPropertyValue*/ false,
                    /*insideComplexValue*/ false,
                    /*propertyName*/ null);

                // Validate the item (for example that it's not null)
                ValidationUtils.ValidateCollectionItem(itemValue, itemType.IsNullable());

                // Note that the ReadNonEntityValue already validated that the actual type of the value matches
                // the expected type (the itemType).
                items.Add(itemValue);
            }

            Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndArray, "The results value must end with an end array.");
            this.JsonReader.ReadEndArray();

            collectionValue.Items = new ReadOnlyEnumerable(items);

            this.DecreaseRecursionDepth();

            return collectionValue;
        }
 public void BuildPropertyContextUriForCollectionPropertyValueWithNonNullAnnotation()
 {
     ODataCollectionValue value = new ODataCollectionValue { TypeName = "FQNS.FromObject" };
     value.SetAnnotation(new SerializationTypeNameAnnotation { TypeName = "FQNS.FromAnnotation" });
     var contextUri = this.CreatePropertyContextUri(value);
     contextUri.OriginalString.Should().Be(BuildExpectedContextUri("#FQNS.FromAnnotation"));
 }
Пример #12
0
        private ODataCollectionValue ReadCollectionValueImplementation(IEdmCollectionTypeReference collectionValueTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation)
        {
            ODataVersionChecker.CheckCollectionValue(base.Version);
            this.IncreaseRecursionDepth();
            base.JsonReader.ReadStartObject();
            ODataCollectionValue value2 = new ODataCollectionValue {
                TypeName = (collectionValueTypeReference != null) ? collectionValueTypeReference.ODataFullName() : payloadTypeName
            };

            if (serializationTypeNameAnnotation != null)
            {
                value2.SetAnnotation <SerializationTypeNameAnnotation>(serializationTypeNameAnnotation);
            }
            List <object> sourceEnumerable = null;
            bool          flag             = false;

            while (base.JsonReader.NodeType == JsonNodeType.Property)
            {
                string strB = base.JsonReader.ReadPropertyName();
                if (string.CompareOrdinal("__metadata", strB) == 0)
                {
                    if (flag)
                    {
                        throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_MultiplePropertiesInCollectionWrapper("__metadata"));
                    }
                    flag = true;
                    base.JsonReader.SkipValue();
                }
                else
                {
                    if (string.CompareOrdinal("results", strB) == 0)
                    {
                        if (sourceEnumerable != null)
                        {
                            throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_MultiplePropertiesInCollectionWrapper("results"));
                        }
                        sourceEnumerable = new List <object>();
                        base.JsonReader.ReadStartArray();
                        DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = base.CreateDuplicatePropertyNamesChecker();
                        IEdmTypeReference             expectedTypeReference         = null;
                        if (collectionValueTypeReference != null)
                        {
                            expectedTypeReference = collectionValueTypeReference.CollectionDefinition().ElementType;
                        }
                        CollectionWithoutExpectedTypeValidator collectionValidator = null;
                        while (base.JsonReader.NodeType != JsonNodeType.EndArray)
                        {
                            object item = this.ReadNonEntityValueImplementation(expectedTypeReference, duplicatePropertyNamesChecker, collectionValidator, true);
                            ValidationUtils.ValidateCollectionItem(item, false);
                            sourceEnumerable.Add(item);
                        }
                        base.JsonReader.ReadEndArray();
                        continue;
                    }
                    base.JsonReader.SkipValue();
                }
            }
            base.JsonReader.ReadEndObject();
            if (sourceEnumerable == null)
            {
                throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_CollectionWithoutResults);
            }
            value2.Items = new ReadOnlyEnumerable(sourceEnumerable);
            this.DecreaseRecursionDepth();
            return(value2);
        }
Пример #13
0
        /// <summary>
        /// Read a collection from the reader.
        /// </summary>
        /// <param name="collectionTypeReference">The type of the collection to read (or null if no type is available).</param>
        /// <param name="payloadTypeName">The name of the collection type specified in the payload.</param>
        /// <param name="serializationTypeNameAnnotation">The serialization type name for the collection value (possibly null).</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.Element    - the element was empty.
        ///                  XmlNodeType.EndElement - the element had some value.
        ///
        /// Note that this method will not read null values, those should be handled by the caller already.
        /// </remarks>
        private ODataCollectionValue ReadCollectionValue(
            IEdmCollectionTypeReference collectionTypeReference,
            string payloadTypeName,
            SerializationTypeNameAnnotation serializationTypeNameAnnotation)
        {
            this.AssertXmlCondition(XmlNodeType.Element, XmlNodeType.Attribute);
            Debug.Assert(
                collectionTypeReference == null || collectionTypeReference.IsNonEntityCollectionType(),
                "If the metadata is specified it must denote a collection for this method to work.");

            this.IncreaseRecursionDepth();

            ODataCollectionValue collectionValue = new ODataCollectionValue();

            // If we have a metadata type for the collection, use that type name
            // otherwise use the type name from the payload (if there was any).
            collectionValue.TypeName = collectionTypeReference == null ? payloadTypeName : collectionTypeReference.FullName();
            if (serializationTypeNameAnnotation != null)
            {
                collectionValue.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();

            List <object> items = new List <object>();

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

                // If we don't have metadata (that is collectionType is null) we parse the type name
                // and extract the item type name from it. Then we create a CollectionWithoutExpectedTypeValidator
                // instance and use it to ensure that all item types read for the collection value are consistent with
                // the item type derived from the collection value's type name.
                // Note that if an item does not specify a type name but the collection value does, the item will be
                // assigned the item type name computed from the collection value's type.
                // Note that JSON doesn't have this problem since in JSON we always have metadata and thus the collectionType
                // is never null by the time we get to a similar place in the code.
                IEdmTypeReference itemTypeReference = collectionTypeReference == null ? null : collectionTypeReference.ElementType();

                DuplicatePropertyNamesChecker          duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker();
                CollectionWithoutExpectedTypeValidator collectionValidator           = null;
                if (collectionTypeReference == null)
                {
                    // Parse the type name from the payload (if any), extract the item type name and construct a collection validator
                    string itemTypeName = payloadTypeName == null ? null : EdmLibraryExtensions.GetCollectionItemTypeName(payloadTypeName);
                    collectionValidator = new CollectionWithoutExpectedTypeValidator(itemTypeName);
                }

                do
                {
                    switch (this.XmlReader.NodeType)
                    {
                    case XmlNodeType.Element:
                        if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataMetadataNamespace))
                        {
                            if (!this.XmlReader.LocalNameEquals(this.ODataCollectionItemElementName))
                            {
                                this.XmlReader.Skip();
                            }
                            else
                            {
                                object itemValue = this.ReadNonEntityValueImplementation(
                                    itemTypeReference,
                                    duplicatePropertyNamesChecker,
                                    collectionValidator,
                                    /*validateNullValue*/ true,
                                    /*propertyName*/ null);

                                // read over the end tag of the element or the start tag if the element was empty.
                                this.XmlReader.Read();

                                // Validate the item (for example that it's not null)
                                ValidationUtils.ValidateCollectionItem(itemValue, itemTypeReference.IsNullable());

                                // Note that the ReadNonEntityValue already validated that the actual type of the value matches
                                // the expected type (the itemType).
                                items.Add(itemValue);
                            }
                        }
                        else if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataNamespace))
                        {
                            throw new ODataException(ODataErrorStrings.ODataAtomPropertyAndValueDeserializer_InvalidCollectionElement(this.XmlReader.LocalName, this.XmlReader.ODataMetadataNamespace));
                        }
                        else
                        {
                            this.XmlReader.Skip();
                        }

                        break;

                    case XmlNodeType.EndElement:
                        // End of the collection.
                        break;

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

            collectionValue.Items = new ReadOnlyEnumerable(items);

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

            this.DecreaseRecursionDepth();

            return(collectionValue);
        }
        /// <summary>
        /// Creates and returns an ODataCollectionValue from the given value.
        /// </summary>
        /// <param name="collectionItemType">The type of the value.</param>
        /// <param name="propertyName">If the value is a property, then it represents the name of the property. Can be null, for non-property.</param>
        /// <param name="value">The value.</param>
        /// <param name="visitedComplexTypeObjects">Set of instances of complex types encountered in the hierarchy. Used to detect cycles.</param>
        /// <param name="isDynamicProperty">Whether this collection property is a dynamic property</param>
        /// <returns>An ODataCollectionValue representing the given value.</returns>
        internal ODataCollectionValue CreateODataCollection(Type collectionItemType, string propertyName, object value, HashSet <object> visitedComplexTypeObjects, bool isDynamicProperty)
        {
            Debug.Assert(collectionItemType != null, "collectionItemType != null");

            WebUtil.ValidateCollection(collectionItemType, value, propertyName, isDynamicProperty);

            PrimitiveType ptype;
            bool          isCollectionOfPrimitiveTypes = PrimitiveType.TryGetPrimitiveType(collectionItemType, out ptype);

            ODataCollectionValue collection = new ODataCollectionValue();
            IEnumerable          enumerablePropertyValue = (IEnumerable)value;
            string collectionItemTypeName;
            string collectionTypeName;

            if (isCollectionOfPrimitiveTypes)
            {
                collectionItemTypeName = ClientConvert.GetEdmType(Nullable.GetUnderlyingType(collectionItemType) ?? collectionItemType);

                if (enumerablePropertyValue != null)
                {
                    collection.Items = Util.GetEnumerable(
                        enumerablePropertyValue,
                        (val) =>
                    {
                        WebUtil.ValidateCollectionItem(val);
                        WebUtil.ValidatePrimitiveCollectionItem(val, propertyName, collectionItemType);
                        return(ConvertPrimitiveValueToRecognizedODataType(val, collectionItemType));
                    });
                }

                // TypeName for primitives should be the EDM name since that's what we will be able to look up in the model
                collectionTypeName = collectionItemTypeName;
            }
            else
            {
                Type collectionItemTypeTmp = Nullable.GetUnderlyingType(collectionItemType) ?? collectionItemType;
                bool areEnumItems          = collectionItemTypeTmp.IsEnum();

                // Note that the collectionItemTypeName will be null if the context does not have the ResolveName func.
                collectionItemTypeName = this.requestInfo.ResolveNameFromType(collectionItemType);

                if (enumerablePropertyValue != null)
                {
                    collection.Items = Util.GetEnumerable(
                        enumerablePropertyValue,
                        (val) =>
                    {
                        if (areEnumItems)
                        {
                            if (val == null)
                            {
                                return(new ODataEnumValue(null, collectionItemType.FullName) as ODataValue);
                            }

                            return(new ODataEnumValue(ClientTypeUtil.GetEnumValuesString(val.ToString(), collectionItemTypeTmp), collectionItemType.FullName) as ODataValue);
                        }
                        else
                        {
                            WebUtil.ValidateCollectionItem(val);
                            WebUtil.ValidateComplexCollectionItem(val, propertyName, collectionItemType);
                            return(this.CreateODataComplexValue(collectionItemType, val, propertyName, true /*isCollectionItem*/, visitedComplexTypeObjects)
                                   as ODataValue);
                        }
                    });
                }

                // TypeName for complex types needs to be the client type name (not the one we resolved above) since it will be looked up in the client model
                collectionTypeName = collectionItemType.FullName;
            }

            // Set the type name to use for client type lookups and validation. Because setting this value can cause validation to occur, we will
            // only do it for JSON Light, in order to avoid breaking changes with the WCF Data Services 5.0 release, since it was already shipped without this.
            if (!this.requestInfo.Format.UsingAtom)
            {
                collection.TypeName = GetCollectionName(collectionTypeName);
            }

            string wireTypeName = GetCollectionName(collectionItemTypeName);

            collection.SetAnnotation(new SerializationTypeNameAnnotation {
                TypeName = wireTypeName
            });
            return(collection);
        }
Пример #15
0
 public void TypeNameShouldComeFromSerializationTypeNameAnnotationForCollectionValue()
 {
     var stna = new SerializationTypeNameAnnotation() {TypeName = "FromSTNA"};
     var value = new ODataCollectionValue() {TypeName = "Collection(Edm.String)"};
     value.SetAnnotation(stna);
     this.typeNameOracle.GetValueTypeNameForWriting(value,
         EdmCoreModel.GetCollection(EdmCoreModel.Instance.GetString(true)),
         EdmCoreModel.GetCollection(EdmCoreModel.Instance.GetString(false)),
         /* isOpenProperty*/ false).Should().Be("FromSTNA");
 }