private static ODataProperty ReadStringPropertyUnderServerKnob(string payload)
 {
     MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(payload));
     ODataMessageReaderSettings settings = new ODataMessageReaderSettings();
     settings.EnableODataServerBehavior();
     ODataAtomInputContext context = new ODataAtomInputContext(ODataFormat.Atom, memoryStream, Encoding.UTF8, settings, false /*readingResponse*/, true /*sync*/, EdmModel, null);
     var deserializer = new ODataAtomPropertyAndValueDeserializer(context);
     return deserializer.ReadTopLevelProperty(StringProperty, StringProperty.Type);
 }
コード例 #2
0
        /// <summary>
        /// Reads the current element's content as an ODataValue.
        /// </summary>
        /// <param name="propertyAndValueDeserializer">The property and value deserializer to use to read values in ATOM.</param>
        /// <param name="expectedType">The expected type of the annotation, may be null if the term is not defined in the model.</param>
        /// <returns>The deserialized value.</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 static ODataValue ReadValueFromElementContent(ODataAtomPropertyAndValueDeserializer propertyAndValueDeserializer, IEdmTypeReference expectedType)
        {
            object result = propertyAndValueDeserializer.ReadNonEntityValue(
                expectedType,
                null /*duplicatePropertyNamesChecker*/,
                null /*collectionValidator*/,
                true /*validateNullValue*/);

            return(result.ToODataValue());
        }
コード例 #3
0
        /// <summary>
        /// Creates a new ATOM annotation parser.
        /// </summary>
        /// <param name="inputContext">The input context this annotation reader should use to read annotation elements.</param>
        /// <param name="propertyAndValueDeserializer">The property and value deserializer to use to read the value of an annotation element.</param>
        internal ODataAtomAnnotationReader(ODataAtomInputContext inputContext, ODataAtomPropertyAndValueDeserializer propertyAndValueDeserializer)
        {
            this.inputContext = inputContext;
            this.propertyAndValueDeserializer = propertyAndValueDeserializer;
            BufferingXmlReader xmlReader = this.inputContext.XmlReader;

            Debug.Assert(xmlReader != null, "xmlReader != null");
            Debug.Assert(xmlReader.NameTable != null, "xmlReader.NameTable != null");
            xmlReader.NameTable.Add(AtomConstants.ODataAnnotationTargetAttribute);
            xmlReader.NameTable.Add(AtomConstants.ODataAnnotationTermAttribute);
            xmlReader.NameTable.Add(AtomConstants.AtomTypeAttributeName);
            xmlReader.NameTable.Add(AtomConstants.ODataNullAttributeName);
            xmlReader.NameTable.Add(AtomConstants.ODataAnnotationStringAttribute);
            xmlReader.NameTable.Add(AtomConstants.ODataAnnotationBoolAttribute);
            xmlReader.NameTable.Add(AtomConstants.ODataAnnotationDecimalAttribute);
            xmlReader.NameTable.Add(AtomConstants.ODataAnnotationIntAttribute);
            xmlReader.NameTable.Add(AtomConstants.ODataAnnotationFloatAttribute);
            this.odataMetadataNamespace = xmlReader.NameTable.Add(AtomConstants.ODataMetadataNamespace);
            this.attributeElementName   = xmlReader.NameTable.Add(AtomConstants.ODataAnnotationElementName);
        }
コード例 #4
0
        /// <summary>
        /// Creates a new ATOM annotation parser.
        /// </summary>
        /// <param name="inputContext">The input context this annotation reader should use to read annotation elements.</param>
        /// <param name="propertyAndValueDeserializer">The property and value deserializer to use to read the value of an annotation element.</param>
        internal ODataAtomAnnotationReader(ODataAtomInputContext inputContext, ODataAtomPropertyAndValueDeserializer propertyAndValueDeserializer)
        {
            this.inputContext = inputContext;
            this.propertyAndValueDeserializer = propertyAndValueDeserializer;
            BufferingXmlReader xmlReader = this.inputContext.XmlReader;

            Debug.Assert(xmlReader != null, "xmlReader != null");
            Debug.Assert(xmlReader.NameTable != null, "xmlReader.NameTable != null");
            xmlReader.NameTable.Add(AtomConstants.ODataAnnotationTargetAttribute);
            xmlReader.NameTable.Add(AtomConstants.ODataAnnotationTermAttribute);
            xmlReader.NameTable.Add(AtomConstants.AtomTypeAttributeName);
            xmlReader.NameTable.Add(AtomConstants.ODataNullAttributeName);
            xmlReader.NameTable.Add(AtomConstants.ODataAnnotationStringAttribute);
            xmlReader.NameTable.Add(AtomConstants.ODataAnnotationBoolAttribute);
            xmlReader.NameTable.Add(AtomConstants.ODataAnnotationDecimalAttribute);
            xmlReader.NameTable.Add(AtomConstants.ODataAnnotationIntAttribute);
            xmlReader.NameTable.Add(AtomConstants.ODataAnnotationFloatAttribute);
            this.odataMetadataNamespace = xmlReader.NameTable.Add(AtomConstants.ODataMetadataNamespace);
            this.attributeElementName = xmlReader.NameTable.Add(AtomConstants.ODataAnnotationElementName);
        }
コード例 #5
0
        /// <summary>
        /// Creates a new instance of this class by consuming xml from the given input context.
        /// </summary>
        /// <param name="inputContext">The input context to use to create the annotation.</param>
        /// <param name="propertyAndValueDeserializer">The property and value deserializer to use when reading values in the annotation element content.</param>
        /// <returns>The <see cref="AtomInstanceAnnotation"/> populated with the information from the 'm:annotation' XML element, as long as the value is a string. Returns null otherwise.</returns>
        /// <remarks>
        /// Pre-Condition:   XmlNodeType.Element    - The annotation element to read.
        /// Post-Condition:  XmlNodeType.Any        - The node after the end of the annotation element, or the same element as in the pre-condition if the annotation was skipped.
        /// </remarks>
        internal static AtomInstanceAnnotation CreateFrom(ODataAtomInputContext inputContext, ODataAtomPropertyAndValueDeserializer propertyAndValueDeserializer)
        {
            var xmlReader = inputContext.XmlReader;

            Debug.Assert(xmlReader != null, "xmlReader != null");
            Debug.Assert(xmlReader.NodeType == XmlNodeType.Element, "xmlReader must be positioned on an Element");
            Debug.Assert(xmlReader.NameTable != null, "xmlReader.NameTable != null");
            Debug.Assert(xmlReader.LocalName == "annotation", "Must be positioned on an annotation element");

            string termAttributeValue                 = null;
            string targetAttributeValue               = null;
            string typeAttributeValue                 = null;
            bool   nullAttributePresentAndTrue        = false;
            bool   sawMultipleAttributeValueNotations = false;

            // Notes on "attribute value notation":
            // Empty elements may have the annotation value specified via an attribute on the annotation element.
            // Exactly one of the following attributes must be present if this notation is being used: "string", "int", "bool", "float", "decimal".
            // The value of the annotation is the value of this value-specifying attribute.
            string attributeValueNotationAttributeName  = null;
            string attributeValueNotationAttributeValue = null;
            IEdmPrimitiveTypeReference attributeValueNotationTypeReference = null;

            XmlNameTable xmlNameTable        = xmlReader.NameTable;
            string       metadataNamespace   = xmlNameTable.Get(AtomConstants.ODataMetadataNamespace);
            string       nullAttributeName   = xmlNameTable.Get(AtomConstants.ODataNullAttributeName);
            string       typeAttributeName   = xmlNameTable.Get(AtomConstants.AtomTypeAttributeName);
            string       emptyNamespace      = xmlNameTable.Get(string.Empty);
            string       termAttributeName   = xmlNameTable.Get(AtomConstants.ODataAnnotationTermAttribute);
            string       targetAttributeName = xmlNameTable.Get(AtomConstants.ODataAnnotationTargetAttribute);

            // Loop through all the attributes and remember the ones specific to annotations.
            while (xmlReader.MoveToNextAttribute())
            {
                if (xmlReader.NamespaceEquals(metadataNamespace))
                {
                    if (xmlReader.LocalNameEquals(typeAttributeName))
                    {
                        typeAttributeValue = xmlReader.Value;
                    }
                    else if (xmlReader.LocalNameEquals(nullAttributeName))
                    {
                        nullAttributePresentAndTrue = ODataAtomReaderUtils.ReadMetadataNullAttributeValue(xmlReader.Value);
                    }

                    // Ignore all other attributes in the metadata namespace.
                    // In general, we only fail on reading if we can't make sense of the document any more. Reader should be loose.
                    // If we choose to start recognizing an additional attribute in the metadata namespace later, be careful not to
                    // fail if it doesn't parse correctly (so that we don't cause a breaking change).
                }
                else if (xmlReader.NamespaceEquals(emptyNamespace))
                {
                    if (xmlReader.LocalNameEquals(termAttributeName))
                    {
                        termAttributeValue = xmlReader.Value;

                        // Before doing any other validation or further reading, check whether or not to read this annotation according to the filter.
                        if (propertyAndValueDeserializer.MessageReaderSettings.ShouldSkipAnnotation(termAttributeValue))
                        {
                            xmlReader.MoveToElement();
                            return(null);
                        }
                    }
                    else if (xmlReader.LocalNameEquals(targetAttributeName))
                    {
                        targetAttributeValue = xmlReader.Value;
                    }
                    else
                    {
                        // Check if this attribute is one used by attribute value notation.
                        IEdmPrimitiveTypeReference potentialTypeFromAttributeValueNotation = LookupEdmTypeByAttributeValueNotationName(xmlReader.LocalName);
                        if (potentialTypeFromAttributeValueNotation != null)
                        {
                            // If we've already seen an attribute used for attribute value notation,
                            // throw since we don't know which type to use (even if the values are the same).
                            // But don't throw yet, because we might not have encountered the term name yet,
                            // and the annotation filter might say to ignore this annotation (and so we shouldn't throw).
                            if (attributeValueNotationTypeReference != null)
                            {
                                sawMultipleAttributeValueNotations = true;
                            }

                            attributeValueNotationTypeReference  = potentialTypeFromAttributeValueNotation;
                            attributeValueNotationAttributeName  = xmlReader.LocalName;
                            attributeValueNotationAttributeValue = xmlReader.Value;
                        }
                    }

                    // Ignore all other attributes in the empty namespace.
                }

                // Ignore all other attributes in all other namespaces.
            }

            xmlReader.MoveToElement();

            // The term attribute is required.
            if (termAttributeValue == null)
            {
                throw new ODataException(ODataErrorStrings.AtomInstanceAnnotation_MissingTermAttributeOnAnnotationElement);
            }

            if (sawMultipleAttributeValueNotations)
            {
                throw new ODataException(ODataErrorStrings.AtomInstanceAnnotation_MultipleAttributeValueNotationAttributes);
            }

            // If this term is defined in the model, look up its type. If the term is not in the model, this will be null.
            IEdmTypeReference expectedTypeReference = MetadataUtils.LookupTypeOfValueTerm(termAttributeValue, propertyAndValueDeserializer.Model);

            ODataValue annotationValue;

            if (nullAttributePresentAndTrue)
            {
                // The m:null attribute has precedence over the content of the element, thus if we find m:null='true' we ignore the content of the element.
                ReaderValidationUtils.ValidateNullValue(
                    propertyAndValueDeserializer.Model,
                    expectedTypeReference,
                    propertyAndValueDeserializer.MessageReaderSettings,
                    /*validateNullValue*/ true,
                    termAttributeValue);
                annotationValue = new ODataNullValue();
            }
            else if (attributeValueNotationTypeReference != null)
            {
                annotationValue = GetValueFromAttributeValueNotation(
                    expectedTypeReference,
                    attributeValueNotationTypeReference,
                    attributeValueNotationAttributeName,
                    attributeValueNotationAttributeValue,
                    typeAttributeValue,
                    xmlReader.IsEmptyElement,
                    propertyAndValueDeserializer.Model,
                    propertyAndValueDeserializer.MessageReaderSettings);
            }
            else
            {
                annotationValue = ReadValueFromElementContent(propertyAndValueDeserializer, expectedTypeReference);
            }

            // Read the end tag (or the start tag if it was an empty element).
            xmlReader.Read();

            return(new AtomInstanceAnnotation(
                       targetAttributeValue,
                       termAttributeValue,
                       annotationValue));
        }
コード例 #6
0
        private void VerifyPrimitiveValueRoundtrips(object clrValue, string edmTypeName, ODataVersion version, string description)
        {
            IEdmModel model = new EdmModel();
            IEdmPrimitiveTypeReference typeReference = new EdmPrimitiveTypeReference((IEdmPrimitiveType)model.FindType(edmTypeName), true);

            MemoryStream stream = new MemoryStream();
            using (ODataAtomOutputContext outputContext = new ODataAtomOutputContext(
                ODataFormat.Atom,
                new NonDisposingStream(stream),
                Encoding.UTF8,
                new ODataMessageWriterSettings() { Version = version },
                /*writingResponse*/ true,
                /*synchronous*/ true,
                model,
                /*urlResolver*/ null))
            {
                ODataAtomPropertyAndValueSerializer serializer = new ODataAtomPropertyAndValueSerializer(outputContext);
                serializer.XmlWriter.WriteStartElement("ValueElement");
                serializer.WritePrimitiveValue(
                    clrValue,
                    /*collectionValidator*/ null,
                    typeReference,
                    /*serializationTypeNameAnnotation*/ null);
                serializer.XmlWriter.WriteEndElement();
            }

            stream.Position = 0;

            object actualValue;
            using (ODataAtomInputContext inputContext = new ODataAtomInputContext(
                ODataFormat.Atom,
                stream,
                Encoding.UTF8,
                new ODataMessageReaderSettings(),
                /*readingResponse*/ true,
                /*synchronous*/ true,
                model,
                /*urlResolver*/ null))
            {
                ODataAtomPropertyAndValueDeserializer deserializer = new ODataAtomPropertyAndValueDeserializer(inputContext);
                deserializer.XmlReader.MoveToContent();
                actualValue = deserializer.ReadNonEntityValue(
                    typeReference,
                    /*duplicatePropertyNamesChecker*/ null,
                    /*collectionValidator*/ null,
                    /*validateNullValue*/ true);
            }

            if (clrValue is byte[])
            {
                ((byte[])actualValue).Should().Equal((byte[])clrValue, description);
            }
            else
            {
                actualValue.Should().Be(clrValue, description);
            }
        }
コード例 #7
0
        /// <summary>
        /// This method creates and reads the property from the input and
        /// returns an <see cref="ODataProperty"/> representing the read property.
        /// </summary>
        /// <param name="property">The <see cref="IEdmProperty"/> producing the property to be read.</param>
        /// <param name="expectedPropertyTypeReference">The expected type reference of the property to read.</param>
        /// <returns>An <see cref="ODataProperty"/> representing the read property.</returns>
        private ODataProperty ReadPropertyImplementation(IEdmStructuralProperty property, IEdmTypeReference expectedPropertyTypeReference)
        {
            ODataAtomPropertyAndValueDeserializer atomPropertyAndValueDeserializer = new ODataAtomPropertyAndValueDeserializer(this);

            return(atomPropertyAndValueDeserializer.ReadTopLevelProperty(property, expectedPropertyTypeReference));
        }
コード例 #8
0
        private void VerifyComplexTypeRoundtrip(ODataComplexValue value, string typeName)
        {
            var typeReference = new EdmComplexTypeReference((IEdmComplexType)model.FindType(typeName), true);
            MemoryStream stream = new MemoryStream();
            using (ODataAtomOutputContext outputContext = new ODataAtomOutputContext(
                ODataFormat.Atom,
                new NonDisposingStream(stream),
                Encoding.UTF8,
                new ODataMessageWriterSettings() { Version = ODataVersion.V4 },
                /*writingResponse*/ true,
                /*synchronous*/ true,
                model,
                /*urlResolver*/ null))
            {
                ODataAtomPropertyAndValueSerializer serializer = new ODataAtomPropertyAndValueSerializer(outputContext);
                serializer.XmlWriter.WriteStartElement("ValueElement");
                serializer.WriteComplexValue(
                    value, 
                    typeReference, 
                    /*isOpenPropertyType*/ false, 
                    /*isWritingCollection*/ false, 
                    /*beforeValueAction*/ null, 
                    /*afterValueAction*/ null, 
                    new DuplicatePropertyNamesChecker(false, false), 
                    /*collectionValidator*/ null, 
                    /*projectedProperties*/ null);
                serializer.XmlWriter.WriteEndElement();
            }

            stream.Position = 0;
            object actualValue;

            using (ODataAtomInputContext inputContext = new ODataAtomInputContext(
                ODataFormat.Atom,
                stream,
                Encoding.UTF8,
                new ODataMessageReaderSettings(),
                /*readingResponse*/ true,
                /*synchronous*/ true,
                model,
                /*urlResolver*/ null))
            {
                ODataAtomPropertyAndValueDeserializer deserializer = new ODataAtomPropertyAndValueDeserializer(inputContext);
                deserializer.XmlReader.MoveToContent();
                actualValue = deserializer.ReadNonEntityValue(
                    typeReference, 
                    /*duplicatePropertyNamesChecker*/ null,
                    /*collectionValidator*/ null, 
                    /*validateNullValue*/ true);
            }

            TestUtils.AssertODataValueAreEqual(actualValue as ODataValue, value);
        }
コード例 #9
0
 /// <summary>
 /// This method creates and reads the property from the input and 
 /// returns an <see cref="ODataProperty"/> representing the read property.
 /// </summary>
 /// <param name="property">The <see cref="IEdmProperty"/> producing the property to be read.</param>
 /// <param name="expectedPropertyTypeReference">The expected type reference of the property to read.</param>
 /// <returns>An <see cref="ODataProperty"/> representing the read property.</returns>
 private ODataProperty ReadPropertyImplementation(IEdmStructuralProperty property, IEdmTypeReference expectedPropertyTypeReference)
 {
     ODataAtomPropertyAndValueDeserializer atomPropertyAndValueDeserializer = new ODataAtomPropertyAndValueDeserializer(this);
     return atomPropertyAndValueDeserializer.ReadTopLevelProperty(property, expectedPropertyTypeReference);
 }
コード例 #10
0
        /// <summary>
        /// Reads the current element's content as an ODataValue.
        /// </summary>
        /// <param name="propertyAndValueDeserializer">The property and value deserializer to use to read values in ATOM.</param>
        /// <param name="expectedType">The expected type of the annotation, may be null if the term is not defined in the model.</param>
        /// <returns>The deserialized value.</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 static ODataValue ReadValueFromElementContent(ODataAtomPropertyAndValueDeserializer propertyAndValueDeserializer, IEdmTypeReference expectedType)
        {
            object result = propertyAndValueDeserializer.ReadNonEntityValue(
                expectedType,
                null /*duplicatePropertyNamesChecker*/,
                null /*collectionValidator*/,
                true /*validateNullValue*/);

            return result.ToODataValue();
        }
コード例 #11
0
        /// <summary>
        /// Creates a new instance of this class by consuming xml from the given input context.
        /// </summary>
        /// <param name="inputContext">The input context to use to create the annotation.</param>
        /// <param name="propertyAndValueDeserializer">The property and value deserializer to use when reading values in the annotation element content.</param>
        /// <returns>The <see cref="AtomInstanceAnnotation"/> populated with the information from the 'm:annotation' XML element, as long as the value is a string. Returns null otherwise.</returns>
        /// <remarks>
        /// Pre-Condition:   XmlNodeType.Element    - The annotation element to read.
        /// Post-Condition:  XmlNodeType.Any        - The node after the end of the annotation element, or the same element as in the pre-condition if the annotation was skipped.
        /// </remarks>
        internal static AtomInstanceAnnotation CreateFrom(ODataAtomInputContext inputContext, ODataAtomPropertyAndValueDeserializer propertyAndValueDeserializer)
        {
            var xmlReader = inputContext.XmlReader;
            Debug.Assert(xmlReader != null, "xmlReader != null");
            Debug.Assert(xmlReader.NodeType == XmlNodeType.Element, "xmlReader must be positioned on an Element");
            Debug.Assert(xmlReader.NameTable != null, "xmlReader.NameTable != null");
            Debug.Assert(xmlReader.LocalName == "annotation", "Must be positioned on an annotation element");

            string termAttributeValue = null;
            string targetAttributeValue = null;
            string typeAttributeValue = null;
            bool nullAttributePresentAndTrue = false;
            bool sawMultipleAttributeValueNotations = false;

            // Notes on "attribute value notation":
            // Empty elements may have the annotation value specified via an attribute on the annotation element.
            // Exactly one of the following attributes must be present if this notation is being used: "string", "int", "bool", "float", "decimal".
            // The value of the annotation is the value of this value-specifying attribute.
            string attributeValueNotationAttributeName = null;
            string attributeValueNotationAttributeValue = null;
            IEdmPrimitiveTypeReference attributeValueNotationTypeReference = null;
            
            XmlNameTable xmlNameTable = xmlReader.NameTable;
            string metadataNamespace = xmlNameTable.Get(AtomConstants.ODataMetadataNamespace);
            string nullAttributeName = xmlNameTable.Get(AtomConstants.ODataNullAttributeName);
            string typeAttributeName = xmlNameTable.Get(AtomConstants.AtomTypeAttributeName);
            string emptyNamespace = xmlNameTable.Get(string.Empty);
            string termAttributeName = xmlNameTable.Get(AtomConstants.ODataAnnotationTermAttribute);
            string targetAttributeName = xmlNameTable.Get(AtomConstants.ODataAnnotationTargetAttribute);

            // Loop through all the attributes and remember the ones specific to annotations.
            while (xmlReader.MoveToNextAttribute())
            {
                if (xmlReader.NamespaceEquals(metadataNamespace))
                {
                    if (xmlReader.LocalNameEquals(typeAttributeName))
                    {
                        typeAttributeValue = xmlReader.Value;
                    }
                    else if (xmlReader.LocalNameEquals(nullAttributeName))
                    {
                        nullAttributePresentAndTrue = ODataAtomReaderUtils.ReadMetadataNullAttributeValue(xmlReader.Value);
                    }

                    // Ignore all other attributes in the metadata namespace.
                    // In general, we only fail on reading if we can't make sense of the document any more. Reader should be loose.
                    // If we choose to start recognizing an additional attribute in the metadata namespace later, be careful not to
                    // fail if it doesn't parse correctly (so that we don't cause a breaking change).
                }
                else if (xmlReader.NamespaceEquals(emptyNamespace))
                {
                    if (xmlReader.LocalNameEquals(termAttributeName))
                    {
                        termAttributeValue = xmlReader.Value;

                        // Before doing any other validation or further reading, check whether or not to read this annotation according to the filter.
                        if (propertyAndValueDeserializer.MessageReaderSettings.ShouldSkipAnnotation(termAttributeValue))
                        {
                            xmlReader.MoveToElement();
                            return null;
                        }
                    }
                    else if (xmlReader.LocalNameEquals(targetAttributeName))
                    {
                        targetAttributeValue = xmlReader.Value;
                    }
                    else
                    {
                        // Check if this attribute is one used by attribute value notation.
                        IEdmPrimitiveTypeReference potentialTypeFromAttributeValueNotation = LookupEdmTypeByAttributeValueNotationName(xmlReader.LocalName);
                        if (potentialTypeFromAttributeValueNotation != null)
                        {
                            // If we've already seen an attribute used for attribute value notation, 
                            // throw since we don't know which type to use (even if the values are the same).
                            // But don't throw yet, because we might not have encountered the term name yet,
                            // and the annotation filter might say to ignore this annotation (and so we shouldn't throw).
                            if (attributeValueNotationTypeReference != null)
                            {
                                sawMultipleAttributeValueNotations = true;
                            }

                            attributeValueNotationTypeReference = potentialTypeFromAttributeValueNotation;
                            attributeValueNotationAttributeName = xmlReader.LocalName;
                            attributeValueNotationAttributeValue = xmlReader.Value;
                        }
                    }

                    // Ignore all other attributes in the empty namespace.
                }

                // Ignore all other attributes in all other namespaces.
            }

            xmlReader.MoveToElement();

            // The term attribute is required.
            if (termAttributeValue == null)
            {
                throw new ODataException(ODataErrorStrings.AtomInstanceAnnotation_MissingTermAttributeOnAnnotationElement);
            }

            if (sawMultipleAttributeValueNotations)
            {
                throw new ODataException(ODataErrorStrings.AtomInstanceAnnotation_MultipleAttributeValueNotationAttributes);
            }
            
            // If this term is defined in the model, look up its type. If the term is not in the model, this will be null.
            IEdmTypeReference expectedTypeReference = MetadataUtils.LookupTypeOfValueTerm(termAttributeValue, propertyAndValueDeserializer.Model);

            ODataValue annotationValue;
            if (nullAttributePresentAndTrue)
            {
                // The m:null attribute has precedence over the content of the element, thus if we find m:null='true' we ignore the content of the element.
                ReaderValidationUtils.ValidateNullValue(
                    propertyAndValueDeserializer.Model, 
                    expectedTypeReference, 
                    propertyAndValueDeserializer.MessageReaderSettings, 
                    /*validateNullValue*/ true,
                    termAttributeValue);
                annotationValue = new ODataNullValue();
            }
            else if (attributeValueNotationTypeReference != null)
            {
                annotationValue = GetValueFromAttributeValueNotation(
                    expectedTypeReference,
                    attributeValueNotationTypeReference,
                    attributeValueNotationAttributeName,
                    attributeValueNotationAttributeValue,
                    typeAttributeValue,
                    xmlReader.IsEmptyElement,
                    propertyAndValueDeserializer.Model,
                    propertyAndValueDeserializer.MessageReaderSettings);
            }
            else
            {
                annotationValue = ReadValueFromElementContent(propertyAndValueDeserializer, expectedTypeReference);
            }

            // Read the end tag (or the start tag if it was an empty element).
            xmlReader.Read();

            return new AtomInstanceAnnotation(
                targetAttributeValue,
                termAttributeValue,
                annotationValue);
        }