internal object ReadCollectionItem(IEdmTypeReference expectedItemType, CollectionWithoutExpectedTypeValidator collectionValidator)
 {
     if (!base.XmlReader.LocalNameEquals(base.ODataCollectionItemElementName))
     {
         throw new ODataException(Microsoft.Data.OData.Strings.ODataAtomCollectionDeserializer_WrongCollectionItemElementName(base.XmlReader.LocalName, base.XmlReader.ODataNamespace));
     }
     object obj2 = base.ReadNonEntityValue(expectedItemType, this.duplicatePropertyNamesChecker, collectionValidator, true, false);
     base.XmlReader.Read();
     return obj2;
 }
 internal void WriteCollectionValue(ODataCollectionValue collectionValue, IEdmTypeReference metadataTypeReference, bool isOpenPropertyType)
 {
     this.IncreaseRecursionDepth();
     base.JsonWriter.StartObjectScope();
     string typeName = collectionValue.TypeName;
     IEdmCollectionTypeReference type = (IEdmCollectionTypeReference) WriterValidationUtils.ResolveTypeNameForWriting(base.Model, metadataTypeReference, ref typeName, EdmTypeKind.Collection, isOpenPropertyType);
     string itemTypeNameFromCollection = null;
     if (typeName != null)
     {
         itemTypeNameFromCollection = ValidationUtils.ValidateCollectionTypeName(typeName);
     }
     SerializationTypeNameAnnotation annotation = collectionValue.GetAnnotation<SerializationTypeNameAnnotation>();
     if (annotation != null)
     {
         typeName = annotation.TypeName;
     }
     if (typeName != null)
     {
         base.JsonWriter.WriteName("__metadata");
         base.JsonWriter.StartObjectScope();
         base.JsonWriter.WriteName("type");
         base.JsonWriter.WriteValue(typeName);
         base.JsonWriter.EndObjectScope();
     }
     base.JsonWriter.WriteDataArrayName();
     base.JsonWriter.StartArrayScope();
     IEnumerable items = collectionValue.Items;
     if (items != null)
     {
         IEdmTypeReference propertyTypeReference = (type == null) ? null : type.ElementType();
         CollectionWithoutExpectedTypeValidator collectionValidator = new CollectionWithoutExpectedTypeValidator(itemTypeNameFromCollection);
         DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = null;
         foreach (object obj2 in items)
         {
             ValidationUtils.ValidateCollectionItem(obj2, false);
             ODataComplexValue complexValue = obj2 as ODataComplexValue;
             if (complexValue != null)
             {
                 if (duplicatePropertyNamesChecker == null)
                 {
                     duplicatePropertyNamesChecker = base.CreateDuplicatePropertyNamesChecker();
                 }
                 this.WriteComplexValue(complexValue, propertyTypeReference, false, duplicatePropertyNamesChecker, collectionValidator);
                 duplicatePropertyNamesChecker.Clear();
             }
             else
             {
                 this.WritePrimitiveValue(obj2, collectionValidator, propertyTypeReference);
             }
         }
     }
     base.JsonWriter.EndArrayScope();
     base.JsonWriter.EndObjectScope();
     this.DecreaseRecursionDepth();
 }
 protected ODataCollectionWriterCore(ODataOutputContext outputContext, IEdmTypeReference expectedItemType, IODataReaderWriterListener listener)
 {
     this.outputContext = outputContext;
     this.expectedItemType = expectedItemType;
     this.listener = listener;
     this.scopes.Push(new Scope(CollectionWriterState.Start, null));
     if (this.expectedItemType == null)
     {
         this.collectionValidator = new CollectionWithoutExpectedTypeValidator(null);
     }
 }
Example #4
0
 protected ODataCollectionWriterCore(ODataOutputContext outputContext, IEdmTypeReference expectedItemType, IODataReaderWriterListener listener)
 {
     this.outputContext    = outputContext;
     this.expectedItemType = expectedItemType;
     this.listener         = listener;
     this.scopes.Push(new Scope(CollectionWriterState.Start, null));
     if (this.expectedItemType == null)
     {
         this.collectionValidator = new CollectionWithoutExpectedTypeValidator(null);
     }
 }
 protected ODataCollectionReaderCore(ODataInputContext inputContext, IEdmTypeReference expectedItemTypeReference, IODataReaderWriterListener listener)
 {
     this.inputContext = inputContext;
     this.expectedItemTypeReference = expectedItemTypeReference;
     if (this.expectedItemTypeReference == null)
     {
         this.collectionValidator = new CollectionWithoutExpectedTypeValidator(null);
     }
     this.listener = listener;
     this.EnterScope(ODataCollectionReaderState.Start, null);
 }
Example #6
0
        /// <summary>
        /// Start writing a collection - implementation of the actual functionality.
        /// </summary>
        /// <param name="collectionStart">The <see cref="ODataCollectionStart"/> representing the collection.</param>
        private void WriteStartImplementation(ODataCollectionStart collectionStart)
        {
            this.StartPayloadInStartState();
            this.EnterScope(CollectionWriterState.Collection, collectionStart);
            this.InterceptException(() =>
            {
                if (this.expectedItemType == null)
                {
                    this.collectionValidator = new CollectionWithoutExpectedTypeValidator(/*expectedItemTypeName*/ null);
                }

                this.StartCollection(collectionStart);
            });
        }
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="outputContext">The output context to write to.</param>
        /// <param name="expectedItemType">The type reference of the expected item type or null if no expected item type exists.</param>
        /// <param name="listener">If not null, the writer will notify the implementer of the interface of relevant state changes in the writer.</param>
        protected ODataCollectionWriterCore(ODataOutputContext outputContext, IEdmTypeReference expectedItemType, IODataReaderWriterListener listener)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(outputContext != null, "outputContext != null");

            this.outputContext    = outputContext;
            this.expectedItemType = expectedItemType;
            this.listener         = listener;
            this.scopes.Push(new Scope(CollectionWriterState.Start, null));

            if (this.expectedItemType == null)
            {
                this.collectionValidator = new CollectionWithoutExpectedTypeValidator(/*expectedItemTypeName*/ null);
            }
        }
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="outputContext">The output context to write to.</param>
        /// <param name="expectedItemType">The type reference of the expected item type or null if no expected item type exists.</param>
        /// <param name="listener">If not null, the writer will notify the implementer of the interface of relevant state changes in the writer.</param>
        protected ODataCollectionWriterCore(ODataOutputContext outputContext, IEdmTypeReference expectedItemType, IODataReaderWriterListener listener)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(outputContext != null, "outputContext != null");

            this.outputContext = outputContext;
            this.expectedItemType = expectedItemType;
            this.listener = listener;
            this.scopes.Push(new Scope(CollectionWriterState.Start, null));

            if (this.expectedItemType == null)
            {
                this.collectionValidator = new CollectionWithoutExpectedTypeValidator(/*expectedItemTypeName*/ null);
            }
        }
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="inputContext">The input to read from.</param>
        /// <param name="expectedItemTypeReference">The expected type reference for the items in the collection.</param>
        /// <param name="listener">If not null, the reader will notify the implementer of the interface of relevant state changes in the reader.</param>
        protected ODataCollectionReaderCore(
            ODataInputContext inputContext,
            IEdmTypeReference expectedItemTypeReference,
            IODataReaderWriterListener listener)
        {
            this.inputContext = inputContext;
            this.expectedItemTypeReference = expectedItemTypeReference;

            if (this.expectedItemTypeReference == null)
            {
                // NOTE: collections cannot specify a type name for the collection itself, so always passing null.
                this.collectionValidator = new CollectionWithoutExpectedTypeValidator(/*expectedItemTypeName*/ null);
            }

            this.listener = listener;
            this.EnterScope(ODataCollectionReaderState.Start, null);
        }
        internal string GetValueTypeNameForWriting(
            object value,
            IEdmTypeReference typeReferenceFromValue,
            SerializationTypeNameAnnotation typeNameAnnotation,
            CollectionWithoutExpectedTypeValidator collectionValidator,
            out string collectionItemTypeName)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(value != null, "value != null");

            collectionItemTypeName = null;

            // if no type name is specified we will use the type name inferred from metadata
            string typeName = GetTypeNameFromValue(value);

            if (typeName == null && typeReferenceFromValue != null)
            {
                typeName = typeReferenceFromValue.ODataFullName();
            }

            if (typeName != null)
            {
                // If the type is the same as the one specified by the parent collection, omit the type name, since it's not needed.
                if (collectionValidator != null && string.CompareOrdinal(collectionValidator.ItemTypeNameFromCollection, typeName) == 0)
                {
                    typeName = null;
                }

                // If value is a collection value, get the item type name.
                if (typeName != null && value is ODataCollectionValue)
                {
                    collectionItemTypeName = ValidationUtils.ValidateCollectionTypeName(typeName);
                }
            }

            if (typeNameAnnotation != null)
            {
                // If the value of TypeName is null, we'll flow it through here, thereby instructing the caller to write no type name.
                typeName = typeNameAnnotation.TypeName;
            }

            return(typeName);
        }
        /// <summary>
        /// Write the items of a collection in ATOM format.
        /// </summary>
        /// <param name="collectionValue">The collection value to write.</param>
        /// <param name="propertyTypeReference">The type reference of the collection (or null if not metadata is available).</param>
        /// <param name="isOpenPropertyType">true if the type name belongs to an open property.</param>
        /// <param name="isWritingCollection">true if we are writing a collection instead of an entry.</param>
        private void WriteCollectionValue(
            ODataCollectionValue collectionValue,
            IEdmTypeReference propertyTypeReference,
            bool isOpenPropertyType,
            bool isWritingCollection)
        {
            Debug.Assert(collectionValue != null, "collectionValue != null");

            this.IncreaseRecursionDepth();

            string typeName = collectionValue.TypeName;

            // resolve the type name to the type; if no type name is specified we will use the 
            // type inferred from metadata
            IEdmCollectionTypeReference collectionTypeReference =
                (IEdmCollectionTypeReference)WriterValidationUtils.ResolveTypeNameForWriting(this.Model, propertyTypeReference, ref typeName, EdmTypeKind.Collection, isOpenPropertyType);

            string collectionItemTypeName = null;
            if (typeName != null)
            {
                collectionItemTypeName = ValidationUtils.ValidateCollectionTypeName(typeName);
            }

            SerializationTypeNameAnnotation serializationTypeNameAnnotation = collectionValue.GetAnnotation<SerializationTypeNameAnnotation>();
            if (serializationTypeNameAnnotation != null)
            {
                typeName = serializationTypeNameAnnotation.TypeName;
            }

            if (typeName != null)
            {
                this.WritePropertyTypeAttribute(typeName);
            }

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

            CollectionWithoutExpectedTypeValidator collectionValidator = new CollectionWithoutExpectedTypeValidator(collectionItemTypeName);

            IEnumerable items = collectionValue.Items;
            if (items != null)
            {
                DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = null;
                foreach (object item in items)
                {
                    ValidationUtils.ValidateCollectionItem(item, false /* isStreamable */);

                    this.XmlWriter.WriteStartElement(AtomConstants.ODataNamespacePrefix, AtomConstants.ODataCollectionItemElementName, this.MessageWriterSettings.WriterBehavior.ODataNamespace);
                    ODataComplexValue complexValue = item as ODataComplexValue;
                    if (complexValue != null)
                    {
                        if (duplicatePropertyNamesChecker == null)
                        {
                            duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker();
                        }

                        this.WriteComplexValue(
                            complexValue,
                            expectedItemTypeReference,
                            false,
                            isWritingCollection,
                            null /* beforeValueAction */,
                            null /* afterValueAction */,
                            duplicatePropertyNamesChecker,
                            collectionValidator,
                            null /* epmValueCache */,
                            null /* epmSourcePathSegment */,
                            null /* projectedProperties */);

                        duplicatePropertyNamesChecker.Clear();
                    }
                    else
                    {
                        Debug.Assert(!(item is ODataCollectionValue), "!(item is ODataCollectionValue)");
                        Debug.Assert(!(item is ODataStreamReferenceValue), "!(item is ODataStreamReferenceValue)");

                        this.WritePrimitiveValue(item, collectionValidator, expectedItemTypeReference);
                    }

                    this.XmlWriter.WriteEndElement();
                }
            }

            this.DecreaseRecursionDepth();
        }
 internal void WriteComplexValue(ODataComplexValue complexValue, IEdmTypeReference propertyTypeReference, bool isOpenPropertyType, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator)
 {
     this.IncreaseRecursionDepth();
     base.JsonWriter.StartObjectScope();
     string typeName = complexValue.TypeName;
     if (collectionValidator != null)
     {
         collectionValidator.ValidateCollectionItem(typeName, EdmTypeKind.Complex);
     }
     IEdmComplexTypeReference type = WriterValidationUtils.ResolveTypeNameForWriting(base.Model, propertyTypeReference, ref typeName, EdmTypeKind.Complex, isOpenPropertyType).AsComplexOrNull();
     if (((typeName != null) && (collectionValidator != null)) && (string.CompareOrdinal(collectionValidator.ItemTypeNameFromCollection, typeName) == 0))
     {
         typeName = null;
     }
     SerializationTypeNameAnnotation annotation = complexValue.GetAnnotation<SerializationTypeNameAnnotation>();
     if (annotation != null)
     {
         typeName = annotation.TypeName;
     }
     if (typeName != null)
     {
         base.JsonWriter.WriteName("__metadata");
         base.JsonWriter.StartObjectScope();
         base.JsonWriter.WriteName("type");
         base.JsonWriter.WriteValue(typeName);
         base.JsonWriter.EndObjectScope();
     }
     this.WriteProperties((type == null) ? null : type.ComplexDefinition(), complexValue.Properties, true, duplicatePropertyNamesChecker, null);
     base.JsonWriter.EndObjectScope();
     this.DecreaseRecursionDepth();
 }
        private object ReadNonEntityValueImplementation(IEdmTypeReference expectedTypeReference, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator, bool validateNullValue, bool epmPresent)
        {
            string itemTypeNameFromCollection;
            bool flag;
            SerializationTypeNameAnnotation annotation;
            EdmTypeKind kind2;
            this.ReadNonEntityValueAttributes(out itemTypeNameFromCollection, out flag);
            if (flag)
            {
                return this.ReadNullValue(expectedTypeReference, validateNullValue);
            }
            bool flag2 = false;
            if ((collectionValidator != null) && (itemTypeNameFromCollection == null))
            {
                itemTypeNameFromCollection = collectionValidator.ItemTypeNameFromCollection;
                flag2 = collectionValidator.ItemTypeKindFromCollection != EdmTypeKind.None;
            }
            IEdmTypeReference type = ReaderValidationUtils.ResolvePayloadTypeNameAndComputeTargetType(EdmTypeKind.None, edmStringType, expectedTypeReference, itemTypeNameFromCollection, base.Model, base.MessageReaderSettings, base.Version, new Func<EdmTypeKind>(this.GetNonEntityValueKind), out kind2, out annotation);
            if (flag2)
            {
                annotation = new SerializationTypeNameAnnotation {
                    TypeName = null
                };
            }
            if (collectionValidator != null)
            {
                collectionValidator.ValidateCollectionItem(itemTypeNameFromCollection, kind2);
            }
            switch (kind2)
            {
                case EdmTypeKind.Primitive:
                    return this.ReadPrimitiveValue(type.AsPrimitive());

                case EdmTypeKind.Complex:
                    return this.ReadComplexValue((type == null) ? null : type.AsComplex(), itemTypeNameFromCollection, annotation, duplicatePropertyNamesChecker, epmPresent);

                case EdmTypeKind.Collection:
                {
                    IEdmCollectionTypeReference collectionTypeReference = ValidationUtils.ValidateCollectionType(type);
                    return this.ReadCollectionValue(collectionTypeReference, itemTypeNameFromCollection, annotation);
                }
            }
            throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.ODataAtomPropertyAndValueDeserializer_ReadNonEntityValue));
        }
 internal void WritePrimitiveValue(object value, CollectionWithoutExpectedTypeValidator collectionValidator, IEdmTypeReference expectedTypeReference)
 {
     IEdmPrimitiveTypeReference primitiveTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(value.GetType());
     if (collectionValidator != null)
     {
         if (primitiveTypeReference == null)
         {
             throw new ODataException(Microsoft.Data.OData.Strings.ValidationUtils_UnsupportedPrimitiveType(value.GetType().FullName));
         }
         collectionValidator.ValidateCollectionItem(primitiveTypeReference.FullName(), EdmTypeKind.Primitive);
     }
     if (expectedTypeReference != null)
     {
         ValidationUtils.ValidateIsExpectedPrimitiveType(value, primitiveTypeReference, expectedTypeReference);
     }
     if ((primitiveTypeReference != null) && primitiveTypeReference.IsSpatial())
     {
         string typeName = primitiveTypeReference.FullName();
         PrimitiveConverter.Instance.WriteJson(value, base.JsonWriter, typeName, base.Version);
     }
     else
     {
         base.JsonWriter.WritePrimitiveValue(value, base.Version);
     }
 }
        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;
        }
 internal void WritePrimitiveValue(object value, CollectionWithoutExpectedTypeValidator collectionValidator, IEdmTypeReference expectedTypeReference)
 {
     IEdmPrimitiveTypeReference primitiveTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(value.GetType());
     if (primitiveTypeReference == null)
     {
         throw new ODataException(Microsoft.Data.OData.Strings.ValidationUtils_UnsupportedPrimitiveType(value.GetType().FullName));
     }
     string collectionItemTypeName = primitiveTypeReference.FullName();
     if (collectionValidator != null)
     {
         collectionValidator.ValidateCollectionItem(collectionItemTypeName, EdmTypeKind.Primitive);
         if (string.CompareOrdinal(collectionValidator.ItemTypeNameFromCollection, collectionItemTypeName) == 0)
         {
             collectionItemTypeName = null;
         }
     }
     if (expectedTypeReference != null)
     {
         ValidationUtils.ValidateIsExpectedPrimitiveType(value, primitiveTypeReference, expectedTypeReference);
     }
     if ((collectionItemTypeName != null) && (collectionItemTypeName != "Edm.String"))
     {
         this.WritePropertyTypeAttribute(collectionItemTypeName);
     }
     AtomValueUtils.WritePrimitiveValue(base.XmlWriter, value);
 }
 internal bool WriteComplexValue(ODataComplexValue complexValue, IEdmTypeReference metadataTypeReference, bool isOpenPropertyType, bool isWritingCollection, Action beforeValueAction, Action afterValueAction, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator, EpmValueCache epmValueCache, EpmSourcePathSegment epmSourcePathSegment, ProjectedPropertiesAnnotation projectedProperties)
 {
     Action action2 = null;
     string typeName = complexValue.TypeName;
     if (collectionValidator != null)
     {
         collectionValidator.ValidateCollectionItem(typeName, EdmTypeKind.Complex);
     }
     this.IncreaseRecursionDepth();
     IEdmComplexTypeReference reference = WriterValidationUtils.ResolveTypeNameForWriting(base.Model, metadataTypeReference, ref typeName, EdmTypeKind.Complex, isOpenPropertyType).AsComplexOrNull();
     if (((typeName != null) && (collectionValidator != null)) && (string.CompareOrdinal(collectionValidator.ItemTypeNameFromCollection, typeName) == 0))
     {
         typeName = null;
     }
     SerializationTypeNameAnnotation annotation = complexValue.GetAnnotation<SerializationTypeNameAnnotation>();
     if (annotation != null)
     {
         typeName = annotation.TypeName;
     }
     Action beforePropertiesAction = beforeValueAction;
     if (typeName != null)
     {
         if (beforeValueAction != null)
         {
             if (action2 == null)
             {
                 action2 = delegate {
                     beforeValueAction();
                     this.WritePropertyTypeAttribute(typeName);
                 };
             }
             beforePropertiesAction = action2;
         }
         else
         {
             this.WritePropertyTypeAttribute(typeName);
         }
     }
     if (((base.MessageWriterSettings.WriterBehavior != null) && base.MessageWriterSettings.WriterBehavior.UseV1ProviderBehavior) && !object.ReferenceEquals(projectedProperties, ProjectedPropertiesAnnotation.EmptyProjectedPropertiesMarker))
     {
         IEdmComplexType definition = (IEdmComplexType) reference.Definition;
         if (base.Model.EpmCachedKeepPrimitiveInContent(definition) == null)
         {
             List<string> keptInContentPropertyNames = null;
             foreach (IEdmProperty property in from p in definition.Properties()
                 where p.Type.IsODataPrimitiveTypeKind()
                 select p)
             {
                 EntityPropertyMappingAttribute entityPropertyMapping = EpmWriterUtils.GetEntityPropertyMapping(epmSourcePathSegment, property.Name);
                 if ((entityPropertyMapping != null) && entityPropertyMapping.KeepInContent)
                 {
                     if (keptInContentPropertyNames == null)
                     {
                         keptInContentPropertyNames = new List<string>();
                     }
                     keptInContentPropertyNames.Add(property.Name);
                 }
             }
             base.Model.SetAnnotationValue<CachedPrimitiveKeepInContentAnnotation>(definition, new CachedPrimitiveKeepInContentAnnotation(keptInContentPropertyNames));
         }
     }
     bool flag = this.WriteProperties((reference == null) ? null : reference.ComplexDefinition(), EpmValueCache.GetComplexValueProperties(epmValueCache, complexValue, true), isWritingCollection, beforePropertiesAction, afterValueAction, duplicatePropertyNamesChecker, epmValueCache, epmSourcePathSegment, projectedProperties);
     this.DecreaseRecursionDepth();
     return flag;
 }
        /// <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;
        }
        private object ReadNonEntityValueImplementation(IEdmTypeReference expectedTypeReference, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator, bool validateNullValue)
        {
            object obj2;
            SerializationTypeNameAnnotation annotation;
            EdmTypeKind kind;
            JsonNodeType nodeType = base.JsonReader.NodeType;
            if (nodeType == JsonNodeType.StartArray)
            {
                throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_CannotReadPropertyValue(nodeType));
            }
            if (this.TryReadNullValue(expectedTypeReference, validateNullValue))
            {
                return null;
            }
            string payloadTypeName = this.FindTypeNameInPayload();
            IEdmTypeReference type = ReaderValidationUtils.ResolvePayloadTypeNameAndComputeTargetType(EdmTypeKind.None, null, expectedTypeReference, payloadTypeName, base.Model, base.MessageReaderSettings, base.Version, new Func<EdmTypeKind>(this.GetNonEntityValueKind), out kind, out annotation);
            switch (kind)
            {
                case EdmTypeKind.Primitive:
                {
                    IEdmPrimitiveTypeReference reference2 = (type == null) ? null : type.AsPrimitive();
                    if ((payloadTypeName != null) && !reference2.IsSpatial())
                    {
                        throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_InvalidPrimitiveTypeName(payloadTypeName));
                    }
                    obj2 = this.ReadPrimitiveValueImplementation(reference2, validateNullValue);
                    break;
                }
                case EdmTypeKind.Complex:
                    obj2 = this.ReadComplexValueImplementation((type == null) ? null : type.AsComplex(), payloadTypeName, annotation, duplicatePropertyNamesChecker);
                    break;

                case EdmTypeKind.Collection:
                {
                    IEdmCollectionTypeReference collectionValueTypeReference = ValidationUtils.ValidateCollectionType(type);
                    obj2 = this.ReadCollectionValueImplementation(collectionValueTypeReference, payloadTypeName, annotation);
                    break;
                }
                default:
                    throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.ODataJsonPropertyAndValueDeserializer_ReadPropertyValue));
            }
            if (collectionValidator != null)
            {
                string collectionItemTypeName = ODataJsonReaderUtils.GetPayloadTypeName(obj2);
                collectionValidator.ValidateCollectionItem(collectionItemTypeName, kind);
            }
            return obj2;
        }
        /// <summary>
        /// Writes out the value of a collection property.
        /// </summary>
        /// <param name="collectionValue">The collection value to write.</param>
        /// <param name="metadataTypeReference">The metadata type reference for the collection.</param>
        /// <param name="isOpenPropertyType">true if the type name belongs to an open property.</param>
        /// <remarks>The current recursion depth is measured by the number of complex and collection values between 
        /// this one and the top-level payload, not including this one.</remarks>
        internal void WriteCollectionValue(
            ODataCollectionValue collectionValue,
            IEdmTypeReference metadataTypeReference,
            bool isOpenPropertyType)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(collectionValue != null, "collectionValue != null");

            this.IncreaseRecursionDepth();

            // Start the object scope which will represent the entire CollectionValue instance
            this.JsonWriter.StartObjectScope();

            // "__metadata": { "type": "typename" }
            // If the CollectionValue has type information write out the metadata and the type in it.
            string typeName = collectionValue.TypeName;

            // resolve the type name to the type; if no type name is specified we will use the 
            // type inferred from metadata
            IEdmCollectionTypeReference collectionTypeReference =
                (IEdmCollectionTypeReference)WriterValidationUtils.ResolveTypeNameForWriting(this.Model, metadataTypeReference, ref typeName, EdmTypeKind.Collection, isOpenPropertyType);

            string collectionItemTypeName = null;
            if (typeName != null)
            {
                collectionItemTypeName = ValidationUtils.ValidateCollectionTypeName(typeName);
            }

            SerializationTypeNameAnnotation serializationTypeNameAnnotation = collectionValue.GetAnnotation<SerializationTypeNameAnnotation>();
            if (serializationTypeNameAnnotation != null)
            {
                typeName = serializationTypeNameAnnotation.TypeName;
            }

            if (typeName != null)
            {
                // Write the __metadata object
                this.JsonWriter.WriteName(JsonConstants.ODataMetadataName);
                this.JsonWriter.StartObjectScope();

                // "type": "typename"
                this.JsonWriter.WriteName(JsonConstants.ODataMetadataTypeName);
                this.JsonWriter.WriteValue(typeName);

                // End the __metadata
                this.JsonWriter.EndObjectScope();
            }

            // "results": [
            // This represents the array of items in the CollectionValue
            this.JsonWriter.WriteDataArrayName();
            this.JsonWriter.StartArrayScope();

            // Iterate through the CollectionValue items and write them out (treat null Items as an empty enumeration)
            IEnumerable items = collectionValue.Items;
            if (items != null)
            {
                IEdmTypeReference expectedItemTypeReference = collectionTypeReference == null ? null : collectionTypeReference.ElementType();

                CollectionWithoutExpectedTypeValidator collectionValidator = new CollectionWithoutExpectedTypeValidator(collectionItemTypeName);

                DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = null;
                foreach (object item in items)
                {
                    ValidationUtils.ValidateCollectionItem(item, false /* isStreamable */);

                    ODataComplexValue itemAsComplexValue = item as ODataComplexValue;
                    if (itemAsComplexValue != null)
                    {
                        if (duplicatePropertyNamesChecker == null)
                        {
                            duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker();
                        }

                        this.WriteComplexValue(
                            itemAsComplexValue,
                            expectedItemTypeReference,
                            false,
                            duplicatePropertyNamesChecker,
                            collectionValidator);

                        duplicatePropertyNamesChecker.Clear();
                    }
                    else
                    {
                        Debug.Assert(!(item is ODataCollectionValue), "!(item is ODataCollectionValue)");
                        Debug.Assert(!(item is ODataStreamReferenceValue), "!(item is ODataStreamReferenceValue)");

                        this.WritePrimitiveValue(item, collectionValidator, expectedItemTypeReference);
                    }
                }
            }

            // End the array scope which holds the items
            this.JsonWriter.EndArrayScope();

            // End the object scope which holds the entire collection
            this.JsonWriter.EndObjectScope();

            this.DecreaseRecursionDepth();
        }
        internal bool WriteComplexValue(
            ODataComplexValue complexValue,
            IEdmTypeReference metadataTypeReference,
            bool isOpenPropertyType,
            bool isWritingCollection,
            Action beforeValueAction,
            Action afterValueAction,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            CollectionWithoutExpectedTypeValidator collectionValidator,
            EpmValueCache epmValueCache,
            EpmSourcePathSegment epmSourcePathSegment,
            ProjectedPropertiesAnnotation projectedProperties)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(complexValue != null, "complexValue != null");

            string typeName = complexValue.TypeName;

            if (collectionValidator != null)
            {
                collectionValidator.ValidateCollectionItem(typeName, EdmTypeKind.Complex);
            }

            this.IncreaseRecursionDepth();

            // resolve the type name to the type; if no type name is specified we will use the 
            // type inferred from metadata
            IEdmComplexTypeReference complexTypeReference =
                WriterValidationUtils.ResolveTypeNameForWriting(this.Model, metadataTypeReference, ref typeName, EdmTypeKind.Complex, isOpenPropertyType).AsComplexOrNull();

            // If the type is the same as the one specified by the parent collection, omit the type name, since it's not needed.
            if (typeName != null && collectionValidator != null)
            {
                string expectedItemTypeName = collectionValidator.ItemTypeNameFromCollection;
                if (string.CompareOrdinal(expectedItemTypeName, typeName) == 0)
                {
                    typeName = null;
                }
            }

            SerializationTypeNameAnnotation serializationTypeNameAnnotation = complexValue.GetAnnotation<SerializationTypeNameAnnotation>();
            if (serializationTypeNameAnnotation != null)
            {
                typeName = serializationTypeNameAnnotation.TypeName;
            }

            Action beforeValueCallbackWithTypeName = beforeValueAction;
            if (typeName != null)
            {
                // The beforeValueAction (if specified) will write the actual property element start.
                // So if we are to write the type attribute, we must postpone that after the start element was written.
                // And so we chain the existing action with our type attribute writing and use that
                // as the before action instead.
                if (beforeValueAction != null)
                {
                    beforeValueCallbackWithTypeName = () =>
                    {
                        beforeValueAction();
                        this.WritePropertyTypeAttribute(typeName);
                    };
                }
                else
                {
                    this.WritePropertyTypeAttribute(typeName);
                }
            }

            // NOTE: see the comments on ODataWriterBehavior.UseV1ProviderBehavior for more information
            // NOTE: We have to check for ProjectedPropertiesAnnotation.Empty here to avoid filling the cache for
            //       complex values we are writing only to ensure we don't have nested EPM-mapped null values 
            //       that will end up in the content eventually.
            if (this.MessageWriterSettings.WriterBehavior != null &&
                this.MessageWriterSettings.WriterBehavior.UseV1ProviderBehavior &&
                !object.ReferenceEquals(projectedProperties, ProjectedPropertiesAnnotation.EmptyProjectedPropertiesMarker))
            {
                IEdmComplexType complexType = (IEdmComplexType)complexTypeReference.Definition;
                CachedPrimitiveKeepInContentAnnotation keepInContentCache = this.Model.EpmCachedKeepPrimitiveInContent(complexType);
                if (keepInContentCache == null)
                {
                    // we are about to write the first value of the given type; compute the keep-in-content information for the primitive properties of this type.
                    List<string> keepInContentPrimitiveProperties = null;

                    // initialize the cache with all primitive properties
                    foreach (IEdmProperty edmProperty in complexType.Properties().Where(p => p.Type.IsODataPrimitiveTypeKind()))
                    {
                        // figure out the keep-in-content value
                        EntityPropertyMappingAttribute entityPropertyMapping = EpmWriterUtils.GetEntityPropertyMapping(epmSourcePathSegment, edmProperty.Name);
                        if (entityPropertyMapping != null && entityPropertyMapping.KeepInContent)
                        {
                            if (keepInContentPrimitiveProperties == null)
                            {
                                keepInContentPrimitiveProperties = new List<string>();
                            }

                            keepInContentPrimitiveProperties.Add(edmProperty.Name);
                        }
                    }

                    this.Model.SetAnnotationValue<CachedPrimitiveKeepInContentAnnotation>(complexType, new CachedPrimitiveKeepInContentAnnotation(keepInContentPrimitiveProperties));
                }
            }

            bool propertyWritten = this.WriteProperties(
                complexTypeReference == null ? null : complexTypeReference.ComplexDefinition(),
                EpmValueCache.GetComplexValueProperties(epmValueCache, complexValue, true),
                isWritingCollection,
                beforeValueCallbackWithTypeName,
                afterValueAction,
                duplicatePropertyNamesChecker,
                epmValueCache,
                epmSourcePathSegment,
                projectedProperties);

            this.DecreaseRecursionDepth();
            return propertyWritten;
        }
        /// <summary>
        /// Writes out the value of a complex property.
        /// </summary>
        /// <param name="complexValue">The complex value to write.</param>
        /// <param name="propertyTypeReference">The metadata type for the complex value.</param>
        /// <param name="isOpenPropertyType">true if the type name belongs to an open property.</param>
        /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</param>
        /// <param name="collectionValidator">The collection validator instance to validate the type names and type kinds of collection items; null if no validation is needed.</param>
        /// <remarks>The current recursion depth should be a value, measured by the number of complex and collection values between
        /// this complex value and the top-level payload, not including this one.</remarks>
        internal void WriteComplexValue(
            ODataComplexValue complexValue,
            IEdmTypeReference propertyTypeReference,
            bool isOpenPropertyType,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            CollectionWithoutExpectedTypeValidator collectionValidator)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(complexValue != null, "complexValue != null");

            this.IncreaseRecursionDepth();

            // Start the object scope which will represent the entire complex instance
            this.JsonWriter.StartObjectScope();

            // Write the "__metadata" : { "type": "typename" }
            // But only if we actually have a typename to write, otherwise we need the __metadata to be omitted entirely
            string typeName = complexValue.TypeName;

            if (collectionValidator != null)
            {
                collectionValidator.ValidateCollectionItem(typeName, EdmTypeKind.Complex);
            }

            // resolve the type name to the type; if no type name is specified we will use the 
            // type inferred from metadata
            IEdmComplexTypeReference complexValueTypeReference =
                WriterValidationUtils.ResolveTypeNameForWriting(this.Model, propertyTypeReference, ref typeName, EdmTypeKind.Complex, isOpenPropertyType).AsComplexOrNull();

            // If the type is the same as the one specified by the parent collection, omit the type name, since it's not needed.
            if (typeName != null && collectionValidator != null)
            {
                string expectedItemTypeName = collectionValidator.ItemTypeNameFromCollection;
                if (string.CompareOrdinal(expectedItemTypeName, typeName) == 0)
                {
                    typeName = null;
                }
            }

            SerializationTypeNameAnnotation serializationTypeNameAnnotation = complexValue.GetAnnotation<SerializationTypeNameAnnotation>();
            if (serializationTypeNameAnnotation != null)
            {
                typeName = serializationTypeNameAnnotation.TypeName;
            }

            if (typeName != null)
            {
                // Write the __metadata object
                this.JsonWriter.WriteName(JsonConstants.ODataMetadataName);
                this.JsonWriter.StartObjectScope();

                // "type": "typename"
                this.JsonWriter.WriteName(JsonConstants.ODataMetadataTypeName);
                this.JsonWriter.WriteValue(typeName);

                // End the __metadata
                this.JsonWriter.EndObjectScope();
            }

            // Write the properties of the complex value as usual. Note we do not allow complex types to contain named stream properties.
            this.WriteProperties(
                complexValueTypeReference == null ? null : complexValueTypeReference.ComplexDefinition(),
                complexValue.Properties,
                true /* isComplexValue */,
                duplicatePropertyNamesChecker,
                null /*projectedProperties */);

            // End the object scope which represents the complex instance
            this.JsonWriter.EndObjectScope();

            this.DecreaseRecursionDepth();
        }
        /// <summary>
        /// Writes a primitive value.
        /// Uses a registered primitive type converter to write the value if one is registered for the type, otherwise directly writes the value.
        /// </summary>
        /// <param name="value">The value to write.</param>
        /// <param name="collectionValidator">The collection validator instance.</param>
        /// <param name="expectedTypeReference">The expected type reference of the primitive value.</param>
        internal void WritePrimitiveValue(
            object value,
            CollectionWithoutExpectedTypeValidator collectionValidator,
            IEdmTypeReference expectedTypeReference)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(value != null, "value != null");

            IEdmPrimitiveTypeReference actualTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(value.GetType());
            if (collectionValidator != null)
            {
                if (actualTypeReference == null)
                {
                    throw new ODataException(o.Strings.ValidationUtils_UnsupportedPrimitiveType(value.GetType().FullName));
                }

                collectionValidator.ValidateCollectionItem(actualTypeReference.FullName(), EdmTypeKind.Primitive);
            }

            if (expectedTypeReference != null)
            {
                ValidationUtils.ValidateIsExpectedPrimitiveType(value, actualTypeReference, expectedTypeReference);
            }

            if (actualTypeReference != null && actualTypeReference.IsSpatial())
            {
                // For spatial types, we will always write the type name. This is consistent with complex types.
                string typeName = actualTypeReference.FullName();
                PrimitiveConverter.Instance.WriteJson(value, this.JsonWriter, typeName, this.Version);
            }
            else
            {
                this.JsonWriter.WritePrimitiveValue(value, this.Version);
            }
        }
 internal object ReadCollectionItem(IEdmTypeReference expectedItemTypeReference, CollectionWithoutExpectedTypeValidator collectionValidator)
 {
     return base.ReadNonEntityValue(expectedItemTypeReference, this.duplicatePropertyNamesChecker, collectionValidator, true);
 }
        /// <summary>
        /// Reads a primitive value, complex value or collection.
        /// </summary>
        /// <param name="expectedValueTypeReference">The expected type reference of the property value.</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use - if null the method should create a new one if necessary.</param>
        /// <param name="collectionValidator">The collection validator instance if no expected item type has been specified; otherwise null.</param>
        /// <param name="validateNullValue">true to validate null values; otherwise false.</param>
        /// <returns>The value of the property read.</returns>
        /// <remarks>
        /// Pre-Condition:  JsonNodeType.PrimitiveValue   - the value of the property is a primitive value
        ///                 JsonNodeType.StartObject      - the value of the property is an object
        ///                 JsonNodeType.StartArray       - the value of the property is an array - method will fail in this case.
        /// Post-Condition: almost anything - the node after the property value.
        ///                 
        /// Returns the value of the property read, which can be one of:
        /// - null
        /// - primitive value
        /// - <see cref="ODataComplexValue"/>
        /// - <see cref="ODataCollectionValue"/>
        /// </remarks>
        internal object ReadNonEntityValue(
            IEdmTypeReference expectedValueTypeReference, 
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            CollectionWithoutExpectedTypeValidator collectionValidator,
            bool validateNullValue)
        {
            DebugUtils.CheckNoExternalCallers();

            this.AssertRecursionDepthIsZero();
            object nonEntityValue = this.ReadNonEntityValueImplementation(expectedValueTypeReference, duplicatePropertyNamesChecker, collectionValidator, validateNullValue);
            this.AssertRecursionDepthIsZero();

            return nonEntityValue;
        }
        /// <summary>
        /// Reads the primitive, complex or collection value.
        /// </summary>
        /// <param name="expectedTypeReference">The expected type reference of the value.</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use (cached), or null if new one should be created.</param>
        /// <param name="collectionValidator">The collection validator instance if no expected item type has been specified; otherwise null.</param>
        /// <param name="validateNullValue">true to validate a null value; otherwise false.</param>
        /// <param name="epmPresent">Whether any EPM mappings exist.</param>
        /// <returns>The value read (null, primitive CLR value, ODataComplexValue or ODataCollectionValue).</returns>
        /// <remarks>
        /// Pre-Condition:   XmlNodeType.Element    - The XML element containing the value to read (also the attributes will be read from it)
        /// Post-Condition:  XmlNodeType.EndElement - The end tag of the element.
        ///                  XmlNodeType.Element    - The empty element node.
        /// </remarks>
        private object ReadNonEntityValueImplementation(
            IEdmTypeReference expectedTypeReference, 
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, 
            CollectionWithoutExpectedTypeValidator collectionValidator,
            bool validateNullValue,
            bool epmPresent)
        {
            this.AssertXmlCondition(XmlNodeType.Element);
            Debug.Assert(
                expectedTypeReference == null || !expectedTypeReference.IsODataEntityTypeKind(),
                "Only primitive, complex or collection types can be read by this method.");
            Debug.Assert(
                expectedTypeReference == null || collectionValidator == null,
                "If an expected value type reference is specified, no collection validator must be provided.");
            this.XmlReader.AssertNotBuffering();

            // Read the attributes looking for m:type and m:null
            string payloadTypeName;
            bool isNull;
            this.ReadNonEntityValueAttributes(out payloadTypeName, out isNull);

            object result;
            if (isNull)
            {
                result = this.ReadNullValue(expectedTypeReference, validateNullValue);
            }
            else
            {
                // If we could derive the item type name from the collection's type name and no type name was specified in the payload
                // fill it in now.
                EdmTypeKind payloadTypeKind;
                bool derivedItemTypeNameFromCollectionTypeName = false;
                if (collectionValidator != null && payloadTypeName == null)
                {
                    payloadTypeName = collectionValidator.ItemTypeNameFromCollection;
                    payloadTypeKind = collectionValidator.ItemTypeKindFromCollection;
                    derivedItemTypeNameFromCollectionTypeName = payloadTypeKind != EdmTypeKind.None;
                }

                // Resolve the payload type name and compute the target type kind and target type reference.
                SerializationTypeNameAnnotation serializationTypeNameAnnotation;
                EdmTypeKind targetTypeKind;
                IEdmTypeReference targetTypeReference = ReaderValidationUtils.ResolvePayloadTypeNameAndComputeTargetType(
                    EdmTypeKind.None,
                    /*defaultPrimitivePayloadType*/ edmStringType,
                    expectedTypeReference,
                    payloadTypeName,
                    this.Model,
                    this.MessageReaderSettings,
                    this.Version,
                    this.GetNonEntityValueKind,
                    out targetTypeKind,
                    out serializationTypeNameAnnotation);

                if (derivedItemTypeNameFromCollectionTypeName)
                {
                    Debug.Assert(
                        serializationTypeNameAnnotation == null,
                        "If we derived the item type name from the collection type name we must not have created a serialization type name annotation.");
                    serializationTypeNameAnnotation = new SerializationTypeNameAnnotation { TypeName = null };
                }

                // If we have no expected type make sure the collection items are of the same kind and specify the same name.
                if (collectionValidator != null)
                {
                    Debug.Assert(expectedTypeReference == null, "If a collection validator is specified there must not be an expected value type reference.");
                    collectionValidator.ValidateCollectionItem(payloadTypeName, targetTypeKind);
                }

                switch (targetTypeKind)
                {
                    case EdmTypeKind.Primitive:
                        Debug.Assert(targetTypeReference != null && targetTypeReference.IsODataPrimitiveTypeKind(), "Expected an OData primitive type.");
                        result = this.ReadPrimitiveValue(targetTypeReference.AsPrimitive());
                        break;

                    case EdmTypeKind.Complex:
                        Debug.Assert(targetTypeReference == null || targetTypeReference.IsComplex(), "Expected a complex type.");
                        result = this.ReadComplexValue(
                            targetTypeReference == null ? null : targetTypeReference.AsComplex(),
                            payloadTypeName,
                            serializationTypeNameAnnotation,
                            duplicatePropertyNamesChecker,
                            epmPresent);
                        break;

                    case EdmTypeKind.Collection:
                        IEdmCollectionTypeReference collectionTypeReference = ValidationUtils.ValidateCollectionType(targetTypeReference);
                        result = this.ReadCollectionValue(
                            collectionTypeReference, 
                            payloadTypeName,
                            serializationTypeNameAnnotation);
                        break;

                    default:
                        throw new ODataException(o.Strings.General_InternalError(InternalErrorCodes.ODataAtomPropertyAndValueDeserializer_ReadNonEntityValue));
                }
            }

            this.AssertXmlCondition(true, XmlNodeType.EndElement);
            this.XmlReader.AssertNotBuffering();
            return result;
        }
        /// <summary>
        /// Reads a primitive, complex or collection value.
        /// </summary>
        /// <param name="expectedTypeReference">The expected type reference of the property value.</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use - if null the method should create a new one if necessary.</param>
        /// <param name="collectionValidator">The collection validator instance if no expected item type has been specified; otherwise null.</param>
        /// <param name="validateNullValue">true to validate null values; otherwise false.</param>
        /// <returns>The value of the property read.</returns>
        /// <remarks>
        /// Pre-Condition:  JsonNodeType.PrimitiveValue   - the value of the property is a primitive value
        ///                 JsonNodeType.StartObject      - the value of the property is an object
        ///                 JsonNodeType.StartArray       - the value of the property is an array - method will fail in this case.
        /// Post-Condition: almost anything - the node after the property value.
        ///                 
        /// Returns the value of the property read, which can be one of:
        /// - null
        /// - primitive value
        /// - <see cref="ODataComplexValue"/>
        /// - <see cref="ODataCollectionValue"/>
        /// </remarks>
        private object ReadNonEntityValueImplementation(
            IEdmTypeReference expectedTypeReference,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            CollectionWithoutExpectedTypeValidator collectionValidator,
            bool validateNullValue)
        {
            // TODO: can we ever get a non-null collection validator here? That would mean that we don't have
            //       an expected type; double-check
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(
                this.JsonReader.NodeType == JsonNodeType.PrimitiveValue || this.JsonReader.NodeType == JsonNodeType.StartObject || this.JsonReader.NodeType == JsonNodeType.StartArray,
                "Pre-Condition: expected JsonNodeType.PrimitiveValue or JsonNodeType.StartObject or JsonNodeType.StartArray");
            Debug.Assert(
                expectedTypeReference == null || !expectedTypeReference.IsODataEntityTypeKind(),
                "Only primitive, complex or collection types can be read by this method.");
            Debug.Assert(
                expectedTypeReference == null || collectionValidator == null,
                "If an expected value type reference is specified, no collection validator must be provided.");
            this.JsonReader.AssertNotBuffering();

            // Property values can be only primitives or objects. No property can have a JSON array value.
            JsonNodeType nodeType = this.JsonReader.NodeType;
            if (nodeType == JsonNodeType.StartArray)
            {
                throw new ODataException(o.Strings.ODataJsonPropertyAndValueDeserializer_CannotReadPropertyValue(nodeType));
            }

            // Try to read a null value
            object result;
            if (this.TryReadNullValue(expectedTypeReference, validateNullValue))
            {
                result = null;
            }
            else
            {
                // Read the payload type name
                string payloadTypeName = this.FindTypeNameInPayload();

                SerializationTypeNameAnnotation serializationTypeNameAnnotation;
                EdmTypeKind targetTypeKind;
                IEdmTypeReference targetTypeReference = ReaderValidationUtils.ResolvePayloadTypeNameAndComputeTargetType(
                    EdmTypeKind.None,
                    /*defaultPrimitivePayloadType*/ null,
                    expectedTypeReference,
                    payloadTypeName,
                    this.Model,
                    this.MessageReaderSettings,
                    this.Version,
                    this.GetNonEntityValueKind,
                    out targetTypeKind,
                    out serializationTypeNameAnnotation);

                switch (targetTypeKind)
                {
                    case EdmTypeKind.Primitive:
                        Debug.Assert(targetTypeReference == null || targetTypeReference.IsODataPrimitiveTypeKind(), "Expected an OData primitive type.");
                        IEdmPrimitiveTypeReference primitiveTargetTypeReference = targetTypeReference == null ? null : targetTypeReference.AsPrimitive();
                        if (payloadTypeName != null && !primitiveTargetTypeReference.IsSpatial())
                        {
                            throw new ODataException(o.Strings.ODataJsonPropertyAndValueDeserializer_InvalidPrimitiveTypeName(payloadTypeName));
                        }

                        result = this.ReadPrimitiveValueImplementation(
                            primitiveTargetTypeReference,
                            validateNullValue);
                        break;
                    case EdmTypeKind.Complex:
                        Debug.Assert(targetTypeReference == null || targetTypeReference.IsComplex(), "Expected a complex type.");
                        result = this.ReadComplexValueImplementation(
                            targetTypeReference == null ? null : targetTypeReference.AsComplex(),
                            payloadTypeName,
                            serializationTypeNameAnnotation,
                            duplicatePropertyNamesChecker);
                        break;
                    case EdmTypeKind.Collection:
                        Debug.Assert(this.Version >= ODataVersion.V3, "Type resolution should already fail if we would decide to read a collection value in V1/V2 payload.");
                        IEdmCollectionTypeReference collectionTypeReference = ValidationUtils.ValidateCollectionType(targetTypeReference);
                        result = this.ReadCollectionValueImplementation(
                            collectionTypeReference,
                            payloadTypeName,
                            serializationTypeNameAnnotation);
                        break;
                    default:
                        throw new ODataException(o.Strings.General_InternalError(InternalErrorCodes.ODataJsonPropertyAndValueDeserializer_ReadPropertyValue));
                }

                // If we have no expected type make sure the collection items are of the same kind and specify the same name.
                if (collectionValidator != null)
                {
                    string payloadTypeNameFromResult = ODataJsonReaderUtils.GetPayloadTypeName(result);
                    Debug.Assert(expectedTypeReference == null, "If a collection validator is specified there must not be an expected value type reference.");
                    collectionValidator.ValidateCollectionItem(payloadTypeNameFromResult, targetTypeKind);
                }
            }

            this.JsonReader.AssertNotBuffering();
            return result;
        }
        /// <summary>
        /// Reads an item in the collection.
        /// </summary>
        /// <param name="expectedItemTypeReference">The expected type of the item to read.</param>
        /// <param name="collectionValidator">The collection validator instance if no expected item type has been specified; otherwise null.</param>
        /// <returns>The value of the collection item that was read; this can be an ODataComplexValue, a primitive value or 'null'.</returns>
        /// <remarks>
        /// Pre-Condition:  The first node of the item in the collection
        ///                 NOTE: this method will throw if the node is not
        ///                 JsonNodeType.StartObject:    for a complex item
        ///                 JsonNodeType.PrimitiveValue: for a primitive item
        /// Post-Condition: The reader is positioned on the first node of the next item or an EndArray node if there are no more items in the collection
        /// </remarks>
        internal object ReadCollectionItem(IEdmTypeReference expectedItemTypeReference, CollectionWithoutExpectedTypeValidator collectionValidator)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(
                expectedItemTypeReference == null ||
                expectedItemTypeReference.IsODataPrimitiveTypeKind() ||
                expectedItemTypeReference.IsODataComplexTypeKind(),
                "If an expected type is specified, it must be a primitive or complex type.");
            this.JsonReader.AssertNotBuffering();

            object item = this.ReadNonEntityValue(
                expectedItemTypeReference, 
                this.duplicatePropertyNamesChecker, 
                collectionValidator,
                /*validateNullValue*/ true);

            this.JsonReader.AssertNotBuffering();

            return item;
        }
 internal object ReadNonEntityValue(IEdmTypeReference expectedValueTypeReference, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator, bool validateNullValue)
 {
     return this.ReadNonEntityValueImplementation(expectedValueTypeReference, duplicatePropertyNamesChecker, collectionValidator, validateNullValue);
 }
        /// <summary>
        /// Reads an item in the collection. 
        /// </summary>
        /// <param name="expectedItemType">The expected type of the item to read.</param>
        /// <param name="collectionValidator">The collection validator instance if no expected item type has been specified; otherwise null.</param>
        /// <returns>The value of the collection item that was read; this can be an ODataComplexValue, a primitive value or 'null'.</returns>
        /// <remarks>
        /// Pre-Condition:  XmlNodeType.Element    - The start element node of the item in the collection.
        /// Post-Condition: Any                    - The next node after the end tag of the item.
        /// </remarks>
        internal object ReadCollectionItem(IEdmTypeReference expectedItemType, CollectionWithoutExpectedTypeValidator collectionValidator)
        {
            DebugUtils.CheckNoExternalCallers();
            this.XmlReader.AssertNotBuffering();
            this.AssertXmlCondition(XmlNodeType.Element);

            // the caller should guarantee that we are reading elements in the OData namespace or the custom namespace specified through the reader settings.
            Debug.Assert(this.XmlReader.NamespaceEquals(this.XmlReader.ODataNamespace), "The 'element' node should be in the OData Namespace or in the user specified Namespace");

            // make sure that the item is named as 'element'.
            if (!this.XmlReader.LocalNameEquals(this.ODataCollectionItemElementName))
            {
                throw new ODataException(o.Strings.ODataAtomCollectionDeserializer_WrongCollectionItemElementName(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 item = this.ReadNonEntityValue(expectedItemType, this.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();

            this.XmlReader.AssertNotBuffering();

            return item;
        }
        /// <summary>
        /// Writes a primitive value.
        /// </summary>
        /// <param name="value">The value to write.</param>
        /// <param name="collectionValidator">The collection validator instance.</param>
        /// <param name="expectedTypeReference">The expected type of the primitive value.</param>
        internal void WritePrimitiveValue(
            object value,
            CollectionWithoutExpectedTypeValidator collectionValidator,
            IEdmTypeReference expectedTypeReference)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(value != null, "value != null");

            IEdmPrimitiveTypeReference primitiveTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(value.GetType());
            if (primitiveTypeReference == null)
            {
                throw new ODataException(o.Strings.ValidationUtils_UnsupportedPrimitiveType(value.GetType().FullName));
            }

            string typeName = primitiveTypeReference.FullName();
            if (collectionValidator != null)
            {
                collectionValidator.ValidateCollectionItem(typeName, EdmTypeKind.Primitive);

                if (string.CompareOrdinal(collectionValidator.ItemTypeNameFromCollection, typeName) == 0)
                {
                    typeName = null;
                }
            }

            if (expectedTypeReference != null)
            {
                ValidationUtils.ValidateIsExpectedPrimitiveType(value, primitiveTypeReference, expectedTypeReference);
            }

            if (typeName != null && typeName != Metadata.EdmConstants.EdmStringTypeName)
            {
                this.WritePropertyTypeAttribute(typeName);
            }

            AtomValueUtils.WritePrimitiveValue(this.XmlWriter, value);
        }
 private void WriteCollectionValue(ODataCollectionValue collectionValue, IEdmTypeReference propertyTypeReference, bool isOpenPropertyType, bool isWritingCollection)
 {
     this.IncreaseRecursionDepth();
     string typeName = collectionValue.TypeName;
     IEdmCollectionTypeReference type = (IEdmCollectionTypeReference) WriterValidationUtils.ResolveTypeNameForWriting(base.Model, propertyTypeReference, ref typeName, EdmTypeKind.Collection, isOpenPropertyType);
     string itemTypeNameFromCollection = null;
     if (typeName != null)
     {
         itemTypeNameFromCollection = ValidationUtils.ValidateCollectionTypeName(typeName);
     }
     SerializationTypeNameAnnotation annotation = collectionValue.GetAnnotation<SerializationTypeNameAnnotation>();
     if (annotation != null)
     {
         typeName = annotation.TypeName;
     }
     if (typeName != null)
     {
         this.WritePropertyTypeAttribute(typeName);
     }
     IEdmTypeReference metadataTypeReference = (type == null) ? null : type.ElementType();
     CollectionWithoutExpectedTypeValidator collectionValidator = new CollectionWithoutExpectedTypeValidator(itemTypeNameFromCollection);
     IEnumerable items = collectionValue.Items;
     if (items != null)
     {
         DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = null;
         foreach (object obj2 in items)
         {
             ValidationUtils.ValidateCollectionItem(obj2, false);
             base.XmlWriter.WriteStartElement("d", "element", base.MessageWriterSettings.WriterBehavior.ODataNamespace);
             ODataComplexValue complexValue = obj2 as ODataComplexValue;
             if (complexValue != null)
             {
                 if (duplicatePropertyNamesChecker == null)
                 {
                     duplicatePropertyNamesChecker = base.CreateDuplicatePropertyNamesChecker();
                 }
                 this.WriteComplexValue(complexValue, metadataTypeReference, false, isWritingCollection, null, null, duplicatePropertyNamesChecker, collectionValidator, null, null, null);
                 duplicatePropertyNamesChecker.Clear();
             }
             else
             {
                 this.WritePrimitiveValue(obj2, collectionValidator, metadataTypeReference);
             }
             base.XmlWriter.WriteEndElement();
         }
     }
     this.DecreaseRecursionDepth();
 }