internal ODataAtomInputContext( ODataFormat format, Stream messageStream, Encoding encoding, ODataMessageReaderSettings messageReaderSettings, ODataVersion version, bool readingResponse, bool synchronous, IEdmModel model, IODataUrlResolver urlResolver) : base(format, messageReaderSettings, version, readingResponse, synchronous, model, urlResolver) { Debug.Assert(messageStream != null, "stream != null"); try { ExceptionUtils.CheckArgumentNotNull(format, "format"); ExceptionUtils.CheckArgumentNotNull(messageReaderSettings, "messageReaderSettings"); this.baseXmlReader = ODataAtomReaderUtils.CreateXmlReader(messageStream, encoding, messageReaderSettings); // For WCF DS Server behavior we need to turn off xml:base processing for V1/V2 back compat. this.xmlReader = new BufferingXmlReader( this.baseXmlReader, /*parentXmlReader*/ null, messageReaderSettings.BaseUri, /*disableXmlBase*/ false, messageReaderSettings.MessageQuotas.MaxNestingDepth); } catch (Exception e) { // Dispose the message stream if we failed to create the input context. if (ExceptionUtils.IsCatchableExceptionType(e) && messageStream != null) { messageStream.Dispose(); } throw; } }
/// <summary> /// Reads the 'type' and 'isNull' attributes of a value. /// </summary> /// <param name="typeName">The value of the 'type' attribute or null if no 'type' attribute exists.</param> /// <param name="isNull">The value of the 'isNull' attribute or null if no 'isNull' attribute exists.</param> /// <remarks> /// Pre-Condition: XmlNodeType.Element - The element to read attributes from. /// Post-Condition: XmlNodeType.Element - The element to read attributes from. /// </remarks> protected void ReadNonEntityValueAttributes(out string typeName, out bool isNull) { this.AssertXmlCondition(XmlNodeType.Element); this.XmlReader.AssertNotBuffering(); typeName = null; isNull = false; while (this.XmlReader.MoveToNextAttribute()) { if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataMetadataNamespace)) { if (this.XmlReader.LocalNameEquals(this.AtomTypeAttributeName)) { // m:type typeName = ReaderUtils.AddEdmPrefixOfTypeName(ReaderUtils.RemovePrefixOfTypeName(this.XmlReader.Value)); } else if (this.XmlReader.LocalNameEquals(this.ODataNullAttributeName)) { // m:null isNull = ODataAtomReaderUtils.ReadMetadataNullAttributeValue(this.XmlReader.Value); // Once we find m:null we stop reading further since m:null trumps any other // content (attributes or elements) break; } //// Ignore all other attributes in the metadata namespace } //// Ignore all other attributes in all other namespaces } this.XmlReader.MoveToElement(); this.AssertXmlCondition(XmlNodeType.Element); this.XmlReader.AssertNotBuffering(); }
/// <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)); }