internal ODataAtomInputContext( ODataFormat format, Stream messageStream, Encoding encoding, ODataMessageReaderSettings messageReaderSettings, bool readingResponse, bool synchronous, IEdmModel model, IODataUrlResolver urlResolver) : base(format, messageReaderSettings, readingResponse, synchronous, model, urlResolver) { Debug.Assert(messageStream != null, "stream != null"); try { ExceptionUtils.CheckArgumentNotNull(format, "format"); ExceptionUtils.CheckArgumentNotNull(messageReaderSettings, "messageReaderSettings"); // Which encoding do we use when reading XML payloads 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 content of an error element. /// </summary> /// <param name="xmlReader">The Xml reader to read the error payload from.</param> /// <param name="maxInnerErrorDepth">The maximumum number of recursive internalexception elements to allow.</param> /// <returns>The <see cref="ODataError"/> representing the error.</returns> /// <remarks> /// This method is used to read top-level errors as well as in-stream errors (from inside the buffering Xml reader). /// Pre-Condition: XmlNodeType.Element - The m:error start element. /// Post-Condition: XmlNodeType.EndElement - The m:error end-element. /// XmlNodeType.Element - The empty m:error start element. /// </remarks> internal static ODataError ReadErrorElement(BufferingXmlReader xmlReader, int maxInnerErrorDepth) { Debug.Assert(xmlReader != null, "this.XmlReader != null"); Debug.Assert(xmlReader.NodeType == XmlNodeType.Element, "xmlReader.NodeType == XmlNodeType.Element"); Debug.Assert(xmlReader.LocalName == AtomConstants.ODataErrorElementName, "Expected reader to be positioned on <m:error> element."); Debug.Assert(xmlReader.NamespaceEquals(xmlReader.ODataMetadataNamespace), "this.XmlReader.NamespaceEquals(atomizedMetadataNamespace)"); ODataError error = new ODataError(); DuplicateErrorElementPropertyBitMask elementsReadBitmask = DuplicateErrorElementPropertyBitMask.None; if (!xmlReader.IsEmptyElement) { // Move to the first child node of the element. xmlReader.Read(); do { switch (xmlReader.NodeType) { case XmlNodeType.EndElement: // end of the <m:error> element continue; case XmlNodeType.Element: if (xmlReader.NamespaceEquals(xmlReader.ODataMetadataNamespace)) { switch (xmlReader.LocalName) { // <m:code> case AtomConstants.ODataErrorCodeElementName: VerifyErrorElementNotFound( ref elementsReadBitmask, DuplicateErrorElementPropertyBitMask.Code, AtomConstants.ODataErrorCodeElementName); error.ErrorCode = xmlReader.ReadElementValue(); continue; // <m:message > case AtomConstants.ODataErrorMessageElementName: VerifyErrorElementNotFound( ref elementsReadBitmask, DuplicateErrorElementPropertyBitMask.Message, AtomConstants.ODataErrorMessageElementName); error.Message = xmlReader.ReadElementValue(); continue; // <m:innererror> case AtomConstants.ODataInnerErrorElementName: VerifyErrorElementNotFound( ref elementsReadBitmask, DuplicateErrorElementPropertyBitMask.InnerError, AtomConstants.ODataInnerErrorElementName); error.InnerError = ReadInnerErrorElement(xmlReader, 0 /* recursionDepth */, maxInnerErrorDepth); continue; default: break; } } break; default: break; } xmlReader.Skip(); } while (xmlReader.NodeType != XmlNodeType.EndElement); } return error; }
/// <summary> /// Reads the content of an inner error element. /// </summary> /// <param name="xmlReader">The (buffering) Xml reader to read the error payload from.</param> /// <param name="recursionDepth">The number of times this function has been called recursively.</param> /// <param name="maxInnerErrorDepth">The maximumum number of recursive internalexception elements to allow.</param> /// <returns>The <see cref="ODataInnerError"/> representing the inner error.</returns> /// <remarks> /// Pre-Condition: XmlNodeType.Element - the m:innererror or m:internalexception element /// Post-Condition: Any - the node after the m:innererror/m:internalexception end element or the node after the empty m:innererror/m:internalexception element node. /// </remarks> private static ODataInnerError ReadInnerErrorElement(BufferingXmlReader xmlReader, int recursionDepth, int maxInnerErrorDepth) { Debug.Assert(xmlReader != null, "this.XmlReader != null"); Debug.Assert(xmlReader.NodeType == XmlNodeType.Element, "xmlReader.NodeType == XmlNodeType.Element"); Debug.Assert( xmlReader.LocalName == AtomConstants.ODataInnerErrorElementName || xmlReader.LocalName == AtomConstants.ODataInnerErrorInnerErrorElementName, "Expected reader to be positioned on 'm:innererror' or 'm:internalexception' element."); Debug.Assert(xmlReader.NamespaceEquals(xmlReader.ODataMetadataNamespace), "this.XmlReader.NamespaceEquals(this.ODataMetadataNamespace)"); ValidationUtils.IncreaseAndValidateRecursionDepth(ref recursionDepth, maxInnerErrorDepth); ODataInnerError innerError = new ODataInnerError(); DuplicateInnerErrorElementPropertyBitMask elementsReadBitmask = DuplicateInnerErrorElementPropertyBitMask.None; if (!xmlReader.IsEmptyElement) { // Move to the first child node of the element. xmlReader.Read(); do { switch (xmlReader.NodeType) { case XmlNodeType.EndElement: // end of the <m:innererror> or <m:internalexception> element continue; case XmlNodeType.Element: if (xmlReader.NamespaceEquals(xmlReader.ODataMetadataNamespace)) { switch (xmlReader.LocalName) { // <m:message> case AtomConstants.ODataInnerErrorMessageElementName: VerifyInnerErrorElementNotFound( ref elementsReadBitmask, DuplicateInnerErrorElementPropertyBitMask.Message, AtomConstants.ODataInnerErrorMessageElementName); innerError.Message = xmlReader.ReadElementValue(); continue; // <m:type> case AtomConstants.ODataInnerErrorTypeElementName: VerifyInnerErrorElementNotFound( ref elementsReadBitmask, DuplicateInnerErrorElementPropertyBitMask.TypeName, AtomConstants.ODataInnerErrorTypeElementName); innerError.TypeName = xmlReader.ReadElementValue(); continue; // <m:stacktrace> case AtomConstants.ODataInnerErrorStackTraceElementName: VerifyInnerErrorElementNotFound( ref elementsReadBitmask, DuplicateInnerErrorElementPropertyBitMask.StackTrace, AtomConstants.ODataInnerErrorStackTraceElementName); innerError.StackTrace = xmlReader.ReadElementValue(); continue; // <m:internalexception> case AtomConstants.ODataInnerErrorInnerErrorElementName: VerifyInnerErrorElementNotFound( ref elementsReadBitmask, DuplicateInnerErrorElementPropertyBitMask.InternalException, AtomConstants.ODataInnerErrorInnerErrorElementName); innerError.InnerError = ReadInnerErrorElement(xmlReader, recursionDepth, maxInnerErrorDepth); continue; default: break; } } break; default: break; } xmlReader.Skip(); } while (xmlReader.NodeType != XmlNodeType.EndElement); } // Read over the end element, or empty start element. xmlReader.Read(); return innerError; }
/// <summary> /// Perform the actual cleanup work. /// </summary> /// <param name="disposing">If 'true' this method is called from user code; if 'false' it is called by the runtime.</param> protected override void Dispose(bool disposing) { if (disposing) { try { if (this.baseXmlReader != null) { ((IDisposable)this.baseXmlReader).Dispose(); } } finally { this.baseXmlReader = null; this.xmlReader = null; } } base.Dispose(disposing); }