File: FrameworkFork\System.ServiceModel\System\ServiceModel\Channels\Message.cs
Web Access
Project: src\src\dotnet-svcutil\lib\src\dotnet-svcutil-lib.csproj (dotnet-svcutil-lib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Runtime;
using System.Runtime.Serialization;
using System.ServiceModel.Diagnostics;
using System.ServiceModel.Dispatcher;
using System.Threading.Tasks;
using Microsoft.Xml;
 
namespace System.ServiceModel.Channels
{
    public abstract class Message : IDisposable
    {
        private MessageState _state;
        internal const int InitialBufferSize = 1024;
 
        public abstract MessageHeaders Headers { get; } // must never return null
 
        protected bool IsDisposed
        {
            get { return _state == MessageState.Closed; }
        }
 
        public virtual bool IsFault
        {
            get
            {
                if (IsDisposed)
                    throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
 
                return false;
            }
        }
 
        public virtual bool IsEmpty
        {
            get
            {
                if (IsDisposed)
                    throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
 
                return false;
            }
        }
 
        public abstract MessageProperties Properties { get; }
 
        public abstract MessageVersion Version { get; } // must never return null
 
        internal virtual RecycledMessageState RecycledMessageState
        {
            get { return null; }
        }
 
        public MessageState State
        {
            get { return _state; }
        }
 
        internal void BodyToString(XmlDictionaryWriter writer)
        {
            OnBodyToString(writer);
        }
 
        public void Close()
        {
            if (_state != MessageState.Closed)
            {
                _state = MessageState.Closed;
                OnClose();
            }
            else
            {
            }
        }
 
        public MessageBuffer CreateBufferedCopy(int maxBufferSize)
        {
            if (maxBufferSize < 0)
                throw TraceUtility.ThrowHelperError(new ArgumentOutOfRangeException("maxBufferSize", maxBufferSize,
                                                    SRServiceModel.ValueMustBeNonNegative), this);
            switch (_state)
            {
                case MessageState.Created:
                    _state = MessageState.Copied;
                    break;
                case MessageState.Closed:
                    throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
                case MessageState.Copied:
                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.MessageHasBeenCopied), this);
                case MessageState.Read:
                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.MessageHasBeenRead), this);
                case MessageState.Written:
                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.MessageHasBeenWritten), this);
                default:
                    Fx.Assert(SRServiceModel.InvalidMessageState);
                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.InvalidMessageState), this);
            }
            return OnCreateBufferedCopy(maxBufferSize);
        }
 
        private static Type GetObjectType(object value)
        {
            return (value == null) ? typeof(object) : value.GetType();
        }
 
        static public Message CreateMessage(MessageVersion version, string action, object body)
        {
            return CreateMessage(version, action, body, DataContractSerializerDefaults.CreateSerializer(GetObjectType(body), int.MaxValue/*maxItems*/));
        }
 
        static public Message CreateMessage(MessageVersion version, string action, object body, XmlObjectSerializer serializer)
        {
            if (version == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version"));
            if (serializer == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("serializer"));
            return new BodyWriterMessage(version, action, new XmlObjectSerializerBodyWriter(body, serializer));
        }
 
        static public Message CreateMessage(MessageVersion version, string action, XmlReader body)
        {
            return CreateMessage(version, action, XmlDictionaryReader.CreateDictionaryReader(body));
        }
 
        static public Message CreateMessage(MessageVersion version, string action, XmlDictionaryReader body)
        {
            if (body == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("body");
            if (version == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("version");
 
            return CreateMessage(version, action, new XmlReaderBodyWriter(body, version.Envelope));
        }
 
        static public Message CreateMessage(MessageVersion version, string action, BodyWriter body)
        {
            if (version == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version"));
            if (body == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("body"));
            return new BodyWriterMessage(version, action, body);
        }
 
        static internal Message CreateMessage(MessageVersion version, ActionHeader actionHeader, BodyWriter body)
        {
            if (version == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version"));
            if (body == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("body"));
            return new BodyWriterMessage(version, actionHeader, body);
        }
 
        static public Message CreateMessage(MessageVersion version, string action)
        {
            if (version == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version"));
            return new BodyWriterMessage(version, action, EmptyBodyWriter.Value);
        }
 
        static internal Message CreateMessage(MessageVersion version, ActionHeader actionHeader)
        {
            if (version == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version"));
            return new BodyWriterMessage(version, actionHeader, EmptyBodyWriter.Value);
        }
 
        static public Message CreateMessage(XmlReader envelopeReader, int maxSizeOfHeaders, MessageVersion version)
        {
            return CreateMessage(XmlDictionaryReader.CreateDictionaryReader(envelopeReader), maxSizeOfHeaders, version);
        }
 
        static public Message CreateMessage(XmlDictionaryReader envelopeReader, int maxSizeOfHeaders, MessageVersion version)
        {
            if (envelopeReader == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("envelopeReader"));
            if (version == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version"));
            Message message = new StreamedMessage(envelopeReader, maxSizeOfHeaders, version);
            return message;
        }
 
        static public Message CreateMessage(MessageVersion version, FaultCode faultCode, string reason, string action)
        {
            if (version == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version"));
            if (faultCode == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("faultCode"));
            if (reason == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("reason"));
 
            return CreateMessage(version, MessageFault.CreateFault(faultCode, reason), action);
        }
 
        static public Message CreateMessage(MessageVersion version, FaultCode faultCode, string reason, object detail, string action)
        {
            if (version == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version"));
            if (faultCode == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("faultCode"));
            if (reason == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("reason"));
 
            return CreateMessage(version, MessageFault.CreateFault(faultCode, new FaultReason(reason), detail), action);
        }
 
        static public Message CreateMessage(MessageVersion version, MessageFault fault, string action)
        {
            if (fault == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("fault"));
            if (version == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version"));
            return new BodyWriterMessage(version, action, new FaultBodyWriter(fault, version.Envelope));
        }
 
        internal Exception CreateMessageDisposedException()
        {
            return new ObjectDisposedException("", SRServiceModel.MessageClosed);
        }
 
        void IDisposable.Dispose()
        {
            Close();
        }
 
        public T GetBody<T>()
        {
            XmlDictionaryReader reader = GetReaderAtBodyContents();   // This call will change the message state to Read.
            return OnGetBody<T>(reader);
        }
 
        protected virtual T OnGetBody<T>(XmlDictionaryReader reader)
        {
            return this.GetBodyCore<T>(reader, DataContractSerializerDefaults.CreateSerializer(typeof(T), int.MaxValue/*maxItems*/));
        }
 
        public T GetBody<T>(XmlObjectSerializer serializer)
        {
            if (serializer == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("serializer"));
            return this.GetBodyCore<T>(GetReaderAtBodyContents(), serializer);
        }
 
        private T GetBodyCore<T>(XmlDictionaryReader reader, XmlObjectSerializer serializer)
        {
            T value;
            using (reader)
            {
                value = (T)serializer.ReadObject(reader);
                this.ReadFromBodyContentsToEnd(reader);
            }
            return value;
        }
 
        internal virtual XmlDictionaryReader GetReaderAtHeader()
        {
            XmlBuffer buffer = new XmlBuffer(int.MaxValue);
            XmlDictionaryWriter writer = buffer.OpenSection(XmlDictionaryReaderQuotas.Max);
            WriteStartEnvelope(writer);
            MessageHeaders headers = this.Headers;
            for (int i = 0; i < headers.Count; i++)
                headers.WriteHeader(i, writer);
            writer.WriteEndElement();
            writer.WriteEndElement();
            buffer.CloseSection();
            buffer.Close();
            XmlDictionaryReader reader = buffer.GetReader(0);
            reader.ReadStartElement();
            reader.MoveToStartElement();
            return reader;
        }
 
        public XmlDictionaryReader GetReaderAtBodyContents()
        {
            EnsureReadMessageState();
            if (IsEmpty)
                throw TraceUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.MessageIsEmpty), this);
            return OnGetReaderAtBodyContents();
        }
 
        internal void EnsureReadMessageState()
        {
            switch (_state)
            {
                case MessageState.Created:
                    _state = MessageState.Read;
                    break;
                case MessageState.Copied:
                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.MessageHasBeenCopied), this);
                case MessageState.Read:
                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.MessageHasBeenRead), this);
                case MessageState.Written:
                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.MessageHasBeenWritten), this);
                case MessageState.Closed:
                    throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
                default:
                    Fx.Assert(SRServiceModel.InvalidMessageState);
                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.InvalidMessageState), this);
            }
        }
 
        internal void InitializeReply(Message request)
        {
            UniqueId requestMessageID = request.Headers.MessageId;
            if (requestMessageID == null)
                throw TraceUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.RequestMessageDoesNotHaveAMessageID), request);
            Headers.RelatesTo = requestMessageID;
        }
 
        static internal bool IsFaultStartElement(XmlDictionaryReader reader, EnvelopeVersion version)
        {
            return reader.IsStartElement(XD.MessageDictionary.Fault, version.DictionaryNamespace);
        }
 
        protected virtual void OnBodyToString(XmlDictionaryWriter writer)
        {
            writer.WriteString(SRServiceModel.MessageBodyIsUnknown);
        }
 
        protected virtual MessageBuffer OnCreateBufferedCopy(int maxBufferSize)
        {
            return OnCreateBufferedCopy(maxBufferSize, XmlDictionaryReaderQuotas.Max);
        }
 
        internal MessageBuffer OnCreateBufferedCopy(int maxBufferSize, XmlDictionaryReaderQuotas quotas)
        {
            XmlBuffer msgBuffer = new XmlBuffer(maxBufferSize);
            XmlDictionaryWriter writer = msgBuffer.OpenSection(quotas);
            OnWriteMessage(writer);
            msgBuffer.CloseSection();
            msgBuffer.Close();
            return new DefaultMessageBuffer(this, msgBuffer);
        }
 
        protected virtual void OnClose()
        {
        }
 
        protected virtual XmlDictionaryReader OnGetReaderAtBodyContents()
        {
            XmlBuffer bodyBuffer = new XmlBuffer(int.MaxValue);
            XmlDictionaryWriter writer = bodyBuffer.OpenSection(XmlDictionaryReaderQuotas.Max);
            if (this.Version.Envelope != EnvelopeVersion.None)
            {
                OnWriteStartEnvelope(writer);
                OnWriteStartBody(writer);
            }
            OnWriteBodyContents(writer);
            if (this.Version.Envelope != EnvelopeVersion.None)
            {
                writer.WriteEndElement();
                writer.WriteEndElement();
            }
            bodyBuffer.CloseSection();
            bodyBuffer.Close();
            XmlDictionaryReader reader = bodyBuffer.GetReader(0);
            if (this.Version.Envelope != EnvelopeVersion.None)
            {
                reader.ReadStartElement();
                reader.ReadStartElement();
            }
            reader.MoveToContent();
            return reader;
        }
 
        protected virtual void OnWriteStartBody(XmlDictionaryWriter writer)
        {
            MessageDictionary messageDictionary = XD.MessageDictionary;
            writer.WriteStartElement(messageDictionary.Prefix.Value, messageDictionary.Body, Version.Envelope.DictionaryNamespace);
        }
 
        public void WriteBodyContents(XmlDictionaryWriter writer)
        {
            EnsureWriteMessageState(writer);
            OnWriteBodyContents(writer);
        }
 
        public Task WriteBodyContentsAsync(XmlDictionaryWriter writer)
        {
            this.WriteBodyContents(writer);
            return TaskHelpers.CompletedTask();
        }
 
        public IAsyncResult BeginWriteBodyContents(XmlDictionaryWriter writer, AsyncCallback callback, object state)
        {
            EnsureWriteMessageState(writer);
            return this.OnBeginWriteBodyContents(writer, callback, state);
        }
 
        public void EndWriteBodyContents(IAsyncResult result)
        {
            this.OnEndWriteBodyContents(result);
        }
 
        protected abstract void OnWriteBodyContents(XmlDictionaryWriter writer);
 
        protected virtual Task OnWriteBodyContentsAsync(XmlDictionaryWriter writer)
        {
            this.OnWriteBodyContents(writer);
            return TaskHelpers.CompletedTask();
        }
 
        protected virtual IAsyncResult OnBeginWriteBodyContents(XmlDictionaryWriter writer, AsyncCallback callback, object state)
        {
            return OnWriteBodyContentsAsync(writer).ToApm(callback, state);
        }
 
        protected virtual void OnEndWriteBodyContents(IAsyncResult result)
        {
            result.ToApmEnd();
        }
 
        public void WriteStartEnvelope(XmlDictionaryWriter writer)
        {
            if (writer == null)
                throw TraceUtility.ThrowHelperError(new ArgumentNullException("writer"), this);
 
            OnWriteStartEnvelope(writer);
        }
 
        protected virtual void OnWriteStartEnvelope(XmlDictionaryWriter writer)
        {
            EnvelopeVersion envelopeVersion = Version.Envelope;
            if (envelopeVersion != EnvelopeVersion.None)
            {
                MessageDictionary messageDictionary = XD.MessageDictionary;
                writer.WriteStartElement(messageDictionary.Prefix.Value, messageDictionary.Envelope, envelopeVersion.DictionaryNamespace);
                WriteSharedHeaderPrefixes(writer);
            }
        }
 
        protected virtual void OnWriteStartHeaders(XmlDictionaryWriter writer)
        {
            EnvelopeVersion envelopeVersion = Version.Envelope;
            if (envelopeVersion != EnvelopeVersion.None)
            {
                MessageDictionary messageDictionary = XD.MessageDictionary;
                writer.WriteStartElement(messageDictionary.Prefix.Value, messageDictionary.Header, envelopeVersion.DictionaryNamespace);
            }
        }
 
        public override string ToString()
        {
            if (IsDisposed)
            {
                return base.ToString();
            }
 
 
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
 
            using (StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture))
            {
                using (XmlWriter textWriter = XmlWriter.Create(stringWriter, settings))
                {
                    using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateDictionaryWriter(textWriter))
                    {
                        try
                        {
                            ToString(writer);
                            writer.Flush();
                            return stringWriter.ToString();
                        }
                        catch (XmlException e)
                        {
                            return string.Format(SRServiceModel.MessageBodyToStringError, e.GetType().ToString(), e.Message);
                        }
                    }
                }
            }
        }
 
        internal void ToString(XmlDictionaryWriter writer)
        {
            if (IsDisposed)
            {
                throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
            }
 
            if (this.Version.Envelope != EnvelopeVersion.None)
            {
                WriteStartEnvelope(writer);
                WriteStartHeaders(writer);
                MessageHeaders headers = this.Headers;
                for (int i = 0; i < headers.Count; i++)
                {
                    headers.WriteHeader(i, writer);
                }
 
                writer.WriteEndElement();
                MessageDictionary messageDictionary = XD.MessageDictionary;
                WriteStartBody(writer);
            }
 
            BodyToString(writer);
 
            if (this.Version.Envelope != EnvelopeVersion.None)
            {
                writer.WriteEndElement();
                writer.WriteEndElement();
            }
        }
 
        public string GetBodyAttribute(string localName, string ns)
        {
            if (localName == null)
                throw TraceUtility.ThrowHelperError(new ArgumentNullException("localName"), this);
            if (ns == null)
                throw TraceUtility.ThrowHelperError(new ArgumentNullException("ns"), this);
            switch (_state)
            {
                case MessageState.Created:
                    break;
                case MessageState.Copied:
                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.MessageHasBeenCopied), this);
                case MessageState.Read:
                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.MessageHasBeenRead), this);
                case MessageState.Written:
                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.MessageHasBeenWritten), this);
                case MessageState.Closed:
                    throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
                default:
                    Fx.Assert(SRServiceModel.InvalidMessageState);
                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.InvalidMessageState), this);
            }
            return OnGetBodyAttribute(localName, ns);
        }
 
        protected virtual string OnGetBodyAttribute(string localName, string ns)
        {
            return null;
        }
 
        internal void ReadFromBodyContentsToEnd(XmlDictionaryReader reader)
        {
            Message.ReadFromBodyContentsToEnd(reader, this.Version.Envelope);
        }
 
        private static void ReadFromBodyContentsToEnd(XmlDictionaryReader reader, EnvelopeVersion envelopeVersion)
        {
            if (envelopeVersion != EnvelopeVersion.None)
            {
                reader.ReadEndElement(); // </Body>
                reader.ReadEndElement(); // </Envelope>
            }
            reader.MoveToContent();
        }
 
        internal static bool ReadStartBody(XmlDictionaryReader reader, EnvelopeVersion envelopeVersion, out bool isFault, out bool isEmpty)
        {
            if (reader.IsEmptyElement)
            {
                reader.Read();
                isEmpty = true;
                isFault = false;
                reader.ReadEndElement();
                return false;
            }
            else
            {
                reader.Read();
                if (reader.NodeType != XmlNodeType.Element)
                    reader.MoveToContent();
                if (reader.NodeType == XmlNodeType.Element)
                {
                    isFault = IsFaultStartElement(reader, envelopeVersion);
                    isEmpty = false;
                }
                else if (reader.NodeType == XmlNodeType.EndElement)
                {
                    isEmpty = true;
                    isFault = false;
                    Message.ReadFromBodyContentsToEnd(reader, envelopeVersion);
                    return false;
                }
                else
                {
                    isEmpty = false;
                    isFault = false;
                }
 
                return true;
            }
        }
 
        public void WriteBody(XmlWriter writer)
        {
            WriteBody(XmlDictionaryWriter.CreateDictionaryWriter(writer));
        }
 
        public void WriteBody(XmlDictionaryWriter writer)
        {
            WriteStartBody(writer);
            WriteBodyContents(writer);
            writer.WriteEndElement();
        }
 
        public void WriteStartBody(XmlWriter writer)
        {
            WriteStartBody(XmlDictionaryWriter.CreateDictionaryWriter(writer));
        }
 
        public void WriteStartBody(XmlDictionaryWriter writer)
        {
            if (writer == null)
                throw TraceUtility.ThrowHelperError(new ArgumentNullException("writer"), this);
            OnWriteStartBody(writer);
        }
 
        internal void WriteStartHeaders(XmlDictionaryWriter writer)
        {
            OnWriteStartHeaders(writer);
        }
 
        public void WriteMessage(XmlWriter writer)
        {
            WriteMessage(XmlDictionaryWriter.CreateDictionaryWriter(writer));
        }
 
        public void WriteMessage(XmlDictionaryWriter writer)
        {
            EnsureWriteMessageState(writer);
            OnWriteMessage(writer);
        }
 
        public virtual Task WriteMessageAsync(XmlWriter writer)
        {
            this.WriteMessage(writer);
            return TaskHelpers.CompletedTask();
        }
 
        public virtual async Task WriteMessageAsync(XmlDictionaryWriter writer)
        {
            EnsureWriteMessageState(writer);
            await this.OnWriteMessageAsync(writer);
        }
 
        public virtual async Task OnWriteMessageAsync(XmlDictionaryWriter writer)
        {
            this.WriteMessagePreamble(writer);
 
            // We should call OnWriteBodyContentsAsync instead of WriteBodyContentsAsync here,
            // otherwise EnsureWriteMessageState would get called twice. Also see OnWriteMessage()
            // for the example.
            await this.OnWriteBodyContentsAsync(writer);
            this.WriteMessagePostamble(writer);
        }
 
        private void EnsureWriteMessageState(XmlDictionaryWriter writer)
        {
            if (writer == null)
                throw TraceUtility.ThrowHelperError(new ArgumentNullException("writer"), this);
            switch (_state)
            {
                case MessageState.Created:
                    _state = MessageState.Written;
                    break;
                case MessageState.Copied:
                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.MessageHasBeenCopied), this);
                case MessageState.Read:
                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.MessageHasBeenRead), this);
                case MessageState.Written:
                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.MessageHasBeenWritten), this);
                case MessageState.Closed:
                    throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
                default:
                    Fx.Assert(SRServiceModel.InvalidMessageState);
                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.InvalidMessageState), this);
            }
        }
 
        //  WriteMessageAsync
        public IAsyncResult BeginWriteMessage(XmlDictionaryWriter writer, AsyncCallback callback, object state)
        {
            EnsureWriteMessageState(writer);
            return OnBeginWriteMessage(writer, callback, state);
        }
 
        public void EndWriteMessage(IAsyncResult result)
        {
            OnEndWriteMessage(result);
        }
 
        //  OnWriteMessageAsync
        protected virtual void OnWriteMessage(XmlDictionaryWriter writer)
        {
            WriteMessagePreamble(writer);
            OnWriteBodyContents(writer);
            WriteMessagePostamble(writer);
        }
 
        internal void WriteMessagePreamble(XmlDictionaryWriter writer)
        {
            if (this.Version.Envelope != EnvelopeVersion.None)
            {
                OnWriteStartEnvelope(writer);
 
                MessageHeaders headers = this.Headers;
                int headersCount = headers.Count;
                if (headersCount > 0)
                {
                    OnWriteStartHeaders(writer);
                    for (int i = 0; i < headersCount; i++)
                    {
                        headers.WriteHeader(i, writer);
                    }
                    writer.WriteEndElement();
                }
 
                OnWriteStartBody(writer);
            }
        }
 
        internal void WriteMessagePostamble(XmlDictionaryWriter writer)
        {
            if (this.Version.Envelope != EnvelopeVersion.None)
            {
                writer.WriteEndElement();
                writer.WriteEndElement();
            }
        }
 
        protected virtual IAsyncResult OnBeginWriteMessage(XmlDictionaryWriter writer, AsyncCallback callback, object state)
        {
            return new OnWriteMessageAsyncResult(writer, this, callback, state);
        }
 
        protected virtual void OnEndWriteMessage(IAsyncResult result)
        {
            OnWriteMessageAsyncResult.End(result);
        }
 
        private void WriteSharedHeaderPrefixes(XmlDictionaryWriter writer)
        {
            MessageHeaders headers = Headers;
            int count = headers.Count;
            int prefixesWritten = 0;
            for (int i = 0; i < count; i++)
            {
                if (this.Version.Addressing == AddressingVersion.None && headers[i].Namespace == AddressingVersion.None.Namespace)
                {
                    continue;
                }
 
                IMessageHeaderWithSharedNamespace headerWithSharedNamespace = headers[i] as IMessageHeaderWithSharedNamespace;
                if (headerWithSharedNamespace != null)
                {
                    XmlDictionaryString prefix = headerWithSharedNamespace.SharedPrefix;
                    string prefixString = prefix.Value;
                    if (!((prefixString.Length == 1)))
                    {
                        Fx.Assert("Message.WriteSharedHeaderPrefixes: (prefixString.Length == 1) -- IMessageHeaderWithSharedNamespace must use a single lowercase letter prefix.");
                        throw TraceUtility.ThrowHelperError(new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "IMessageHeaderWithSharedNamespace must use a single lowercase letter prefix.")), this);
                    }
 
                    int prefixIndex = prefixString[0] - 'a';
                    if (!((prefixIndex >= 0 && prefixIndex < 26)))
                    {
                        Fx.Assert("Message.WriteSharedHeaderPrefixes: (prefixIndex >= 0 && prefixIndex < 26) -- IMessageHeaderWithSharedNamespace must use a single lowercase letter prefix.");
                        throw TraceUtility.ThrowHelperError(new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "IMessageHeaderWithSharedNamespace must use a single lowercase letter prefix.")), this);
                    }
                    int prefixBit = 1 << prefixIndex;
                    if ((prefixesWritten & prefixBit) == 0)
                    {
                        writer.WriteXmlnsAttribute(prefixString, headerWithSharedNamespace.SharedNamespace);
                        prefixesWritten |= prefixBit;
                    }
                }
            }
        }
 
 
        private class OnWriteMessageAsyncResult : ScheduleActionItemAsyncResult
        {
            private Message _message;
            private XmlDictionaryWriter _writer;
 
            public OnWriteMessageAsyncResult(XmlDictionaryWriter writer, Message message, AsyncCallback callback, object state)
                : base(callback, state)
            {
                Fx.Assert(message != null, "message should never be null");
 
                _message = message;
                _writer = writer;
 
                Schedule();
            }
 
            protected override void OnDoWork()
            {
                _message.OnWriteMessage(_writer);
            }
        }
    }
 
    internal class EmptyBodyWriter : BodyWriter
    {
        private static EmptyBodyWriter s_value;
 
        private EmptyBodyWriter()
            : base(true)
        {
        }
 
        public static EmptyBodyWriter Value
        {
            get
            {
                if (s_value == null)
                    s_value = new EmptyBodyWriter();
                return s_value;
            }
        }
 
        internal override bool IsEmpty
        {
            get { return true; }
        }
 
        protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
        {
        }
    }
 
    internal class FaultBodyWriter : BodyWriter
    {
        private MessageFault _fault;
        private EnvelopeVersion _version;
 
        public FaultBodyWriter(MessageFault fault, EnvelopeVersion version)
            : base(true)
        {
            _fault = fault;
            _version = version;
        }
 
        internal override bool IsFault
        {
            get { return true; }
        }
 
        protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
        {
            _fault.WriteTo(writer, _version);
        }
    }
 
    internal class XmlObjectSerializerBodyWriter : BodyWriter
    {
        private object _body;
        private XmlObjectSerializer _serializer;
 
        public XmlObjectSerializerBodyWriter(object body, XmlObjectSerializer serializer)
            : base(true)
        {
            _body = body;
            _serializer = serializer;
        }
 
        private object ThisLock
        {
            get { return this; }
        }
 
        protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
        {
            lock (ThisLock)
            {
                _serializer.WriteObject(writer, _body);
            }
        }
    }
 
    internal class XmlReaderBodyWriter : BodyWriter
    {
        private XmlDictionaryReader _reader;
        private bool _isFault;
 
        public XmlReaderBodyWriter(XmlDictionaryReader reader, EnvelopeVersion version)
            : base(false)
        {
            _reader = reader;
            if (reader.MoveToContent() != XmlNodeType.Element)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SRServiceModel.InvalidReaderPositionOnCreateMessage, "reader"));
 
            _isFault = Message.IsFaultStartElement(reader, version);
        }
 
        internal override bool IsFault
        {
            get
            {
                return _isFault;
            }
        }
 
        protected override BodyWriter OnCreateBufferedCopy(int maxBufferSize)
        {
            return OnCreateBufferedCopy(maxBufferSize, _reader.Quotas);
        }
 
        protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
        {
            using (_reader)
            {
                XmlNodeType type = _reader.MoveToContent();
                while (!_reader.EOF && type != XmlNodeType.EndElement)
                {
                    if (type != XmlNodeType.Element)
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SRServiceModel.InvalidReaderPositionOnCreateMessage, "reader"));
                    writer.WriteNode(_reader, false);
 
                    type = _reader.MoveToContent();
                }
            }
        }
    }
 
    internal class BodyWriterMessage : Message
    {
        private MessageProperties _properties;
        private MessageHeaders _headers;
        private BodyWriter _bodyWriter;
 
        private BodyWriterMessage(BodyWriter bodyWriter)
        {
            _bodyWriter = bodyWriter;
        }
 
        public BodyWriterMessage(MessageVersion version, string action, BodyWriter bodyWriter)
            : this(bodyWriter)
        {
            _headers = new MessageHeaders(version);
            _headers.Action = action;
        }
 
        public BodyWriterMessage(MessageVersion version, ActionHeader actionHeader, BodyWriter bodyWriter)
            : this(bodyWriter)
        {
            _headers = new MessageHeaders(version);
            _headers.SetActionHeader(actionHeader);
        }
 
        public BodyWriterMessage(MessageHeaders headers, KeyValuePair<string, object>[] properties, BodyWriter bodyWriter)
            : this(bodyWriter)
        {
            _headers = new MessageHeaders(headers);
            _properties = new MessageProperties(properties);
        }
 
        public override bool IsFault
        {
            get
            {
                if (IsDisposed)
                    throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
                return _bodyWriter.IsFault;
            }
        }
 
        public override bool IsEmpty
        {
            get
            {
                if (IsDisposed)
                    throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
                return _bodyWriter.IsEmpty;
            }
        }
 
        public override MessageHeaders Headers
        {
            get
            {
                if (IsDisposed)
                    throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
                return _headers;
            }
        }
 
        public override MessageProperties Properties
        {
            get
            {
                if (IsDisposed)
                    throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
                if (_properties == null)
                    _properties = new MessageProperties();
                return _properties;
            }
        }
 
        public override MessageVersion Version
        {
            get
            {
                if (IsDisposed)
                    throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
                return _headers.MessageVersion;
            }
        }
 
        protected override MessageBuffer OnCreateBufferedCopy(int maxBufferSize)
        {
            BodyWriter bufferedBodyWriter;
            if (_bodyWriter.IsBuffered)
            {
                bufferedBodyWriter = _bodyWriter;
            }
            else
            {
                bufferedBodyWriter = _bodyWriter.CreateBufferedCopy(maxBufferSize);
            }
            KeyValuePair<string, object>[] properties = new KeyValuePair<string, object>[Properties.Count];
            ((ICollection<KeyValuePair<string, object>>)Properties).CopyTo(properties, 0);
            return new BodyWriterMessageBuffer(_headers, properties, bufferedBodyWriter);
        }
 
        protected override void OnClose()
        {
            Exception ex = null;
            try
            {
                base.OnClose();
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                    throw;
                ex = e;
            }
 
            try
            {
                if (_properties != null)
                    _properties.Dispose();
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                    throw;
                if (ex == null)
                    ex = e;
            }
 
            if (ex != null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(ex);
 
            _bodyWriter = null;
        }
 
        protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
        {
            _bodyWriter.WriteBodyContents(writer);
        }
 
        protected override Task OnWriteBodyContentsAsync(XmlDictionaryWriter writer)
        {
            return _bodyWriter.WriteBodyContentsAsync(writer);
        }
 
        protected override IAsyncResult OnBeginWriteMessage(XmlDictionaryWriter writer, AsyncCallback callback, object state)
        {
            return null;
            //WriteMessagePreamble(writer);
            //return new OnWriteMessageAsyncResult(writer, this, callback, state);
        }
 
        protected override void OnEndWriteMessage(IAsyncResult result)
        {
            //OnWriteMessageAsyncResult.End(result);
        }
 
        protected override IAsyncResult OnBeginWriteBodyContents(XmlDictionaryWriter writer, AsyncCallback callback, object state)
        {
            return _bodyWriter.BeginWriteBodyContents(writer, callback, state);
        }
 
        protected override void OnEndWriteBodyContents(IAsyncResult result)
        {
            _bodyWriter.EndWriteBodyContents(result);
        }
 
        protected override void OnBodyToString(XmlDictionaryWriter writer)
        {
            if (_bodyWriter.IsBuffered)
            {
                _bodyWriter.WriteBodyContents(writer);
            }
            else
            {
                writer.WriteString(SRServiceModel.MessageBodyIsStream);
            }
        }
 
        protected internal BodyWriter BodyWriter
        {
            get
            {
                return _bodyWriter;
            }
        }
 
        private class OnWriteMessageAsyncResult : AsyncResult
        {
            private BodyWriterMessage _message;
            private XmlDictionaryWriter _writer;
 
            public OnWriteMessageAsyncResult(XmlDictionaryWriter writer, BodyWriterMessage message, AsyncCallback callback, object state)
                : base(callback, state)
            {
                _message = message;
                _writer = writer;
 
                if (HandleWriteBodyContents(null))
                {
                    this.Complete(true);
                }
            }
 
            private bool HandleWriteBodyContents(IAsyncResult result)
            {
                if (result == null)
                {
                    result = _message.OnBeginWriteBodyContents(_writer, PrepareAsyncCompletion(HandleWriteBodyContents), this);
                    if (!result.CompletedSynchronously)
                    {
                        return false;
                    }
                }
 
                _message.OnEndWriteBodyContents(result);
                _message.WriteMessagePostamble(_writer);
                return true;
            }
 
            public static void End(IAsyncResult result)
            {
                AsyncResult.End<OnWriteMessageAsyncResult>(result);
            }
        }
    }
 
    internal abstract class ReceivedMessage : Message
    {
        private bool _isFault;
        private bool _isEmpty;
 
        public override bool IsEmpty
        {
            get { return _isEmpty; }
        }
 
        public override bool IsFault
        {
            get { return _isFault; }
        }
 
        protected static bool HasHeaderElement(XmlDictionaryReader reader, EnvelopeVersion envelopeVersion)
        {
            return reader.IsStartElement(XD.MessageDictionary.Header, envelopeVersion.DictionaryNamespace);
        }
 
        protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
        {
            if (!_isEmpty)
            {
                using (XmlDictionaryReader bodyReader = OnGetReaderAtBodyContents())
                {
                    if (bodyReader.ReadState == ReadState.Error || bodyReader.ReadState == ReadState.Closed)
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(string.Format(SRServiceModel.MessageBodyReaderInvalidReadState, bodyReader.ReadState.ToString())));
 
                    while (bodyReader.NodeType != XmlNodeType.EndElement && !bodyReader.EOF)
                    {
                        writer.WriteNode(bodyReader, false);
                    }
 
                    this.ReadFromBodyContentsToEnd(bodyReader);
                }
            }
        }
 
        protected bool ReadStartBody(XmlDictionaryReader reader)
        {
            return Message.ReadStartBody(reader, this.Version.Envelope, out _isFault, out _isEmpty);
        }
 
        protected static EnvelopeVersion ReadStartEnvelope(XmlDictionaryReader reader)
        {
            EnvelopeVersion envelopeVersion;
 
            if (reader.IsStartElement(XD.MessageDictionary.Envelope, XD.Message12Dictionary.Namespace))
                envelopeVersion = EnvelopeVersion.Soap12;
            else if (reader.IsStartElement(XD.MessageDictionary.Envelope, XD.Message11Dictionary.Namespace))
                envelopeVersion = EnvelopeVersion.Soap11;
            else
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SRServiceModel.MessageVersionUnknown));
            if (reader.IsEmptyElement)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SRServiceModel.MessageBodyMissing));
            reader.Read();
            return envelopeVersion;
        }
 
        protected static void VerifyStartBody(XmlDictionaryReader reader, EnvelopeVersion version)
        {
            if (!reader.IsStartElement(XD.MessageDictionary.Body, version.DictionaryNamespace))
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SRServiceModel.MessageBodyMissing));
        }
    }
 
    internal sealed class StreamedMessage : ReceivedMessage
    {
        private MessageHeaders _headers;
        private XmlAttributeHolder[] _envelopeAttributes;
        private XmlAttributeHolder[] _headerAttributes;
        private XmlAttributeHolder[] _bodyAttributes;
        private string _envelopePrefix;
        private string _headerPrefix;
        private string _bodyPrefix;
        private MessageProperties _properties;
        private XmlDictionaryReader _reader;
        private XmlDictionaryReaderQuotas _quotas;
 
        public StreamedMessage(XmlDictionaryReader reader, int maxSizeOfHeaders, MessageVersion desiredVersion)
        {
            _properties = new MessageProperties();
            if (reader.NodeType != XmlNodeType.Element)
                reader.MoveToContent();
 
            if (desiredVersion.Envelope == EnvelopeVersion.None)
            {
                _reader = reader;
                _headerAttributes = XmlAttributeHolder.emptyArray;
                _headers = new MessageHeaders(desiredVersion);
            }
            else
            {
                _envelopeAttributes = XmlAttributeHolder.ReadAttributes(reader, ref maxSizeOfHeaders);
                _envelopePrefix = reader.Prefix;
                EnvelopeVersion envelopeVersion = ReadStartEnvelope(reader);
                if (desiredVersion.Envelope != envelopeVersion)
                {
                    Exception versionMismatchException = new ArgumentException(string.Format(SRServiceModel.EncoderEnvelopeVersionMismatch, envelopeVersion, desiredVersion.Envelope), "reader");
                    throw TraceUtility.ThrowHelperError(
                        new CommunicationException(versionMismatchException.Message, versionMismatchException),
                        this);
                }
 
                if (HasHeaderElement(reader, envelopeVersion))
                {
                    _headerPrefix = reader.Prefix;
                    _headerAttributes = XmlAttributeHolder.ReadAttributes(reader, ref maxSizeOfHeaders);
                    _headers = new MessageHeaders(desiredVersion, reader, _envelopeAttributes, _headerAttributes, ref maxSizeOfHeaders);
                }
                else
                {
                    _headerAttributes = XmlAttributeHolder.emptyArray;
                    _headers = new MessageHeaders(desiredVersion);
                }
 
                if (reader.NodeType != XmlNodeType.Element)
                    reader.MoveToContent();
                _bodyPrefix = reader.Prefix;
                VerifyStartBody(reader, envelopeVersion);
                _bodyAttributes = XmlAttributeHolder.ReadAttributes(reader, ref maxSizeOfHeaders);
                if (ReadStartBody(reader))
                {
                    _reader = reader;
                }
                else
                {
                    _quotas = new XmlDictionaryReaderQuotas();
                    reader.Quotas.CopyTo(_quotas);
                    reader.Dispose();
                }
            }
        }
 
        public override MessageHeaders Headers
        {
            get
            {
                if (IsDisposed)
                    throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
                return _headers;
            }
        }
 
        public override MessageVersion Version
        {
            get
            {
                return _headers.MessageVersion;
            }
        }
 
        public override MessageProperties Properties
        {
            get
            {
                return _properties;
            }
        }
 
        protected override void OnBodyToString(XmlDictionaryWriter writer)
        {
            writer.WriteString(SRServiceModel.MessageBodyIsStream);
        }
 
        protected override void OnClose()
        {
            Exception ex = null;
            try
            {
                base.OnClose();
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                    throw;
                ex = e;
            }
 
            try
            {
                _properties.Dispose();
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                    throw;
                if (ex == null)
                    ex = e;
            }
 
            try
            {
                if (_reader != null)
                {
                    _reader.Dispose();
                }
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                    throw;
                if (ex == null)
                    ex = e;
            }
 
            if (ex != null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(ex);
        }
 
        protected override XmlDictionaryReader OnGetReaderAtBodyContents()
        {
            XmlDictionaryReader reader = _reader;
            _reader = null;
            return reader;
        }
 
        protected override MessageBuffer OnCreateBufferedCopy(int maxBufferSize)
        {
            if (_reader != null)
                return OnCreateBufferedCopy(maxBufferSize, _reader.Quotas);
            return OnCreateBufferedCopy(maxBufferSize, _quotas);
        }
 
        protected override void OnWriteStartBody(XmlDictionaryWriter writer)
        {
            writer.WriteStartElement(_bodyPrefix, MessageStrings.Body, Version.Envelope.Namespace);
            XmlAttributeHolder.WriteAttributes(_bodyAttributes, writer);
        }
 
        protected override void OnWriteStartEnvelope(XmlDictionaryWriter writer)
        {
            EnvelopeVersion envelopeVersion = Version.Envelope;
            writer.WriteStartElement(_envelopePrefix, MessageStrings.Envelope, envelopeVersion.Namespace);
            XmlAttributeHolder.WriteAttributes(_envelopeAttributes, writer);
        }
 
        protected override void OnWriteStartHeaders(XmlDictionaryWriter writer)
        {
            EnvelopeVersion envelopeVersion = Version.Envelope;
            writer.WriteStartElement(_headerPrefix, MessageStrings.Header, envelopeVersion.Namespace);
            XmlAttributeHolder.WriteAttributes(_headerAttributes, writer);
        }
 
        protected override string OnGetBodyAttribute(string localName, string ns)
        {
            return XmlAttributeHolder.GetAttribute(_bodyAttributes, localName, ns);
        }
    }
 
    internal interface IBufferedMessageData
    {
        MessageEncoder MessageEncoder { get; }
        ArraySegment<byte> Buffer { get; }
        XmlDictionaryReaderQuotas Quotas { get; }
        void Close();
        void EnableMultipleUsers();
        XmlDictionaryReader GetMessageReader();
        void Open();
        void ReturnMessageState(RecycledMessageState messageState);
        RecycledMessageState TakeMessageState();
    }
 
    internal sealed class BufferedMessage : ReceivedMessage
    {
        private MessageHeaders _headers;
        private MessageProperties _properties;
        private IBufferedMessageData _messageData;
        private RecycledMessageState _recycledMessageState;
        private XmlDictionaryReader _reader;
        private XmlAttributeHolder[] _bodyAttributes;
 
        public BufferedMessage(IBufferedMessageData messageData, RecycledMessageState recycledMessageState)
            : this(messageData, recycledMessageState, null, false)
        {
        }
 
        public BufferedMessage(IBufferedMessageData messageData, RecycledMessageState recycledMessageState, bool[] understoodHeaders, bool understoodHeadersModified)
        {
            bool throwing = true;
            try
            {
                _recycledMessageState = recycledMessageState;
                _messageData = messageData;
                _properties = recycledMessageState.TakeProperties();
                if (_properties == null)
                    _properties = new MessageProperties();
                XmlDictionaryReader reader = messageData.GetMessageReader();
                MessageVersion desiredVersion = messageData.MessageEncoder.MessageVersion;
 
                if (desiredVersion.Envelope == EnvelopeVersion.None)
                {
                    _reader = reader;
                    _headers = new MessageHeaders(desiredVersion);
                }
                else
                {
                    EnvelopeVersion envelopeVersion = ReadStartEnvelope(reader);
                    if (desiredVersion.Envelope != envelopeVersion)
                    {
                        Exception versionMismatchException = new ArgumentException(string.Format(SRServiceModel.EncoderEnvelopeVersionMismatch, envelopeVersion, desiredVersion.Envelope), "reader");
                        throw TraceUtility.ThrowHelperError(
                            new CommunicationException(versionMismatchException.Message, versionMismatchException),
                            this);
                    }
 
                    if (HasHeaderElement(reader, envelopeVersion))
                    {
                        _headers = recycledMessageState.TakeHeaders();
                        if (_headers == null)
                        {
                            _headers = new MessageHeaders(desiredVersion, reader, messageData, recycledMessageState, understoodHeaders, understoodHeadersModified);
                        }
                        else
                        {
                            _headers.Init(desiredVersion, reader, messageData, recycledMessageState, understoodHeaders, understoodHeadersModified);
                        }
                    }
                    else
                    {
                        _headers = new MessageHeaders(desiredVersion);
                    }
 
                    VerifyStartBody(reader, envelopeVersion);
 
                    int maxSizeOfAttributes = int.MaxValue;
                    _bodyAttributes = XmlAttributeHolder.ReadAttributes(reader, ref maxSizeOfAttributes);
                    if (maxSizeOfAttributes < int.MaxValue - 4096)
                        _bodyAttributes = null;
                    if (ReadStartBody(reader))
                    {
                        _reader = reader;
                    }
                    else
                    {
                        reader.Dispose();
                    }
                }
                throwing = false;
            }
            finally
            {
                if (throwing && MessageLogger.LoggingEnabled)
                {
                    MessageLogger.LogMessage(messageData.Buffer, MessageLoggingSource.Malformed);
                }
            }
        }
 
        public override MessageHeaders Headers
        {
            get
            {
                if (IsDisposed)
                    throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
                return _headers;
            }
        }
 
        internal IBufferedMessageData MessageData
        {
            get
            {
                return _messageData;
            }
        }
 
        public override MessageProperties Properties
        {
            get
            {
                if (IsDisposed)
                    throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
                return _properties;
            }
        }
 
        internal override RecycledMessageState RecycledMessageState
        {
            get { return _recycledMessageState; }
        }
 
        public override MessageVersion Version
        {
            get
            {
                return _headers.MessageVersion;
            }
        }
 
        protected override XmlDictionaryReader OnGetReaderAtBodyContents()
        {
            XmlDictionaryReader reader = _reader;
            _reader = null;
            return reader;
        }
 
        internal override XmlDictionaryReader GetReaderAtHeader()
        {
            if (!_headers.ContainsOnlyBufferedMessageHeaders)
                return base.GetReaderAtHeader();
            XmlDictionaryReader reader = _messageData.GetMessageReader();
            if (reader.NodeType != XmlNodeType.Element)
                reader.MoveToContent();
            reader.Read();
            if (HasHeaderElement(reader, _headers.MessageVersion.Envelope))
                return reader;
            return base.GetReaderAtHeader();
        }
 
        public XmlDictionaryReader GetBufferedReaderAtBody()
        {
            XmlDictionaryReader reader = _messageData.GetMessageReader();
            if (reader.NodeType != XmlNodeType.Element)
                reader.MoveToContent();
            if (this.Version.Envelope != EnvelopeVersion.None)
            {
                reader.Read();
                if (HasHeaderElement(reader, _headers.MessageVersion.Envelope))
                    reader.Skip();
                if (reader.NodeType != XmlNodeType.Element)
                    reader.MoveToContent();
            }
            return reader;
        }
 
        public XmlDictionaryReader GetMessageReader()
        {
            return _messageData.GetMessageReader();
        }
 
        protected override void OnBodyToString(XmlDictionaryWriter writer)
        {
            using (XmlDictionaryReader reader = GetBufferedReaderAtBody())
            {
                if (this.Version == MessageVersion.None)
                {
                    writer.WriteNode(reader, false);
                }
                else
                {
                    if (!reader.IsEmptyElement)
                    {
                        reader.ReadStartElement();
                        while (reader.NodeType != XmlNodeType.EndElement)
                            writer.WriteNode(reader, false);
                    }
                }
            }
        }
 
        protected override void OnClose()
        {
            Exception ex = null;
            try
            {
                base.OnClose();
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                    throw;
                ex = e;
            }
 
            try
            {
                _properties.Dispose();
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                    throw;
                if (ex == null)
                    ex = e;
            }
 
            try
            {
                if (_reader != null)
                {
                    _reader.Dispose();
                }
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                    throw;
                if (ex == null)
                    ex = e;
            }
 
            try
            {
                _recycledMessageState.ReturnHeaders(_headers);
                _recycledMessageState.ReturnProperties(_properties);
                _messageData.ReturnMessageState(_recycledMessageState);
                _recycledMessageState = null;
                _messageData.Close();
                _messageData = null;
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                    throw;
                if (ex == null)
                    ex = e;
            }
 
            if (ex != null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(ex);
        }
 
        protected override void OnWriteStartEnvelope(XmlDictionaryWriter writer)
        {
            using (XmlDictionaryReader reader = GetMessageReader())
            {
                reader.MoveToContent();
                EnvelopeVersion envelopeVersion = Version.Envelope;
                writer.WriteStartElement(reader.Prefix, MessageStrings.Envelope, envelopeVersion.Namespace);
                writer.WriteAttributes(reader, false);
            }
        }
 
        protected override void OnWriteStartHeaders(XmlDictionaryWriter writer)
        {
            using (XmlDictionaryReader reader = GetMessageReader())
            {
                reader.MoveToContent();
                EnvelopeVersion envelopeVersion = Version.Envelope;
                reader.Read();
                if (HasHeaderElement(reader, envelopeVersion))
                {
                    writer.WriteStartElement(reader.Prefix, MessageStrings.Header, envelopeVersion.Namespace);
                    writer.WriteAttributes(reader, false);
                }
                else
                {
                    writer.WriteStartElement(MessageStrings.Prefix, MessageStrings.Header, envelopeVersion.Namespace);
                }
            }
        }
 
        protected override void OnWriteStartBody(XmlDictionaryWriter writer)
        {
            using (XmlDictionaryReader reader = GetBufferedReaderAtBody())
            {
                writer.WriteStartElement(reader.Prefix, MessageStrings.Body, Version.Envelope.Namespace);
                writer.WriteAttributes(reader, false);
            }
        }
 
        protected override MessageBuffer OnCreateBufferedCopy(int maxBufferSize)
        {
            if (_headers.ContainsOnlyBufferedMessageHeaders)
            {
                KeyValuePair<string, object>[] properties = new KeyValuePair<string, object>[Properties.Count];
                ((ICollection<KeyValuePair<string, object>>)Properties).CopyTo(properties, 0);
                _messageData.EnableMultipleUsers();
                bool[] understoodHeaders = null;
                if (_headers.HasMustUnderstandBeenModified)
                {
                    understoodHeaders = new bool[_headers.Count];
                    for (int i = 0; i < _headers.Count; i++)
                    {
                        understoodHeaders[i] = _headers.IsUnderstood(i);
                    }
                }
                return new BufferedMessageBuffer(_messageData, properties, understoodHeaders, _headers.HasMustUnderstandBeenModified);
            }
            else
            {
                if (_reader != null)
                    return OnCreateBufferedCopy(maxBufferSize, _reader.Quotas);
                return OnCreateBufferedCopy(maxBufferSize, XmlDictionaryReaderQuotas.Max);
            }
        }
 
        protected override string OnGetBodyAttribute(string localName, string ns)
        {
            if (_bodyAttributes != null)
                return XmlAttributeHolder.GetAttribute(_bodyAttributes, localName, ns);
            using (XmlDictionaryReader reader = GetBufferedReaderAtBody())
            {
                return reader.GetAttribute(localName, ns);
            }
        }
    }
 
    internal struct XmlAttributeHolder
    {
        private string _prefix;
        private string _ns;
        private string _localName;
        private string _value;
 
        public static XmlAttributeHolder[] emptyArray = new XmlAttributeHolder[0];
 
        public XmlAttributeHolder(string prefix, string localName, string ns, string value)
        {
            _prefix = prefix;
            _localName = localName;
            _ns = ns;
            _value = value;
        }
 
        public string Prefix
        {
            get { return _prefix; }
        }
 
        public string NamespaceUri
        {
            get { return _ns; }
        }
 
        public string LocalName
        {
            get { return _localName; }
        }
 
        public string Value
        {
            get { return _value; }
        }
 
        public void WriteTo(XmlWriter writer)
        {
            writer.WriteStartAttribute(_prefix, _localName, _ns);
            writer.WriteString(_value);
            writer.WriteEndAttribute();
        }
 
        public static void WriteAttributes(XmlAttributeHolder[] attributes, XmlWriter writer)
        {
            for (int i = 0; i < attributes.Length; i++)
                attributes[i].WriteTo(writer);
        }
 
        public static XmlAttributeHolder[] ReadAttributes(XmlDictionaryReader reader)
        {
            int maxSizeOfHeaders = int.MaxValue;
            return ReadAttributes(reader, ref maxSizeOfHeaders);
        }
 
        public static XmlAttributeHolder[] ReadAttributes(XmlDictionaryReader reader, ref int maxSizeOfHeaders)
        {
            if (reader.AttributeCount == 0)
                return emptyArray;
            XmlAttributeHolder[] attributes = new XmlAttributeHolder[reader.AttributeCount];
            reader.MoveToFirstAttribute();
            for (int i = 0; i < attributes.Length; i++)
            {
                string ns = reader.NamespaceURI;
                string localName = reader.LocalName;
                string prefix = reader.Prefix;
                string value = string.Empty;
                while (reader.ReadAttributeValue())
                {
                    if (value.Length == 0)
                        value = reader.Value;
                    else
                        value += reader.Value;
                }
                Deduct(prefix, ref maxSizeOfHeaders);
                Deduct(localName, ref maxSizeOfHeaders);
                Deduct(ns, ref maxSizeOfHeaders);
                Deduct(value, ref maxSizeOfHeaders);
                attributes[i] = new XmlAttributeHolder(prefix, localName, ns, value);
                reader.MoveToNextAttribute();
            }
            reader.MoveToElement();
            return attributes;
        }
 
        private static void Deduct(string s, ref int maxSizeOfHeaders)
        {
            int byteCount = s.Length * sizeof(char);
            if (byteCount > maxSizeOfHeaders)
            {
                string message = SRServiceModel.XmlBufferQuotaExceeded;
                Exception inner = new QuotaExceededException(message);
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(message, inner));
            }
            maxSizeOfHeaders -= byteCount;
        }
 
        public static string GetAttribute(XmlAttributeHolder[] attributes, string localName, string ns)
        {
            for (int i = 0; i < attributes.Length; i++)
                if (attributes[i].LocalName == localName && attributes[i].NamespaceUri == ns)
                    return attributes[i].Value;
            return null;
        }
    }
 
    internal class RecycledMessageState
    {
        private MessageHeaders _recycledHeaders;
        private MessageProperties _recycledProperties;
        private UriCache _uriCache;
        private HeaderInfoCache _headerInfoCache;
 
        public HeaderInfoCache HeaderInfoCache
        {
            get
            {
                if (_headerInfoCache == null)
                {
                    _headerInfoCache = new HeaderInfoCache();
                }
                return _headerInfoCache;
            }
        }
 
        public UriCache UriCache
        {
            get
            {
                if (_uriCache == null)
                    _uriCache = new UriCache();
                return _uriCache;
            }
        }
 
        public MessageProperties TakeProperties()
        {
            MessageProperties taken = _recycledProperties;
            _recycledProperties = null;
            return taken;
        }
 
        public void ReturnProperties(MessageProperties properties)
        {
            if (properties.CanRecycle)
            {
                properties.Recycle();
                _recycledProperties = properties;
            }
        }
 
        public MessageHeaders TakeHeaders()
        {
            MessageHeaders taken = _recycledHeaders;
            _recycledHeaders = null;
            return taken;
        }
 
        public void ReturnHeaders(MessageHeaders headers)
        {
            if (headers.CanRecycle)
            {
                headers.Recycle(this.HeaderInfoCache);
                _recycledHeaders = headers;
            }
        }
    }
 
    internal class HeaderInfoCache
    {
        private const int maxHeaderInfos = 4;
        private HeaderInfo[] _headerInfos;
        private int _index;
 
        public MessageHeaderInfo TakeHeaderInfo(XmlDictionaryReader reader, string actor, bool mustUnderstand, bool relay, bool isRefParam)
        {
            if (_headerInfos != null)
            {
                int i = _index;
                for (; ; )
                {
                    HeaderInfo headerInfo = _headerInfos[i];
                    if (headerInfo != null)
                    {
                        if (headerInfo.Matches(reader, actor, mustUnderstand, relay, isRefParam))
                        {
                            _headerInfos[i] = null;
                            _index = (i + 1) % maxHeaderInfos;
                            return headerInfo;
                        }
                    }
                    i = (i + 1) % maxHeaderInfos;
                    if (i == _index)
                    {
                        break;
                    }
                }
            }
 
            return new HeaderInfo(reader, actor, mustUnderstand, relay, isRefParam);
        }
 
        public void ReturnHeaderInfo(MessageHeaderInfo headerInfo)
        {
            HeaderInfo headerInfoToReturn = headerInfo as HeaderInfo;
            if (headerInfoToReturn != null)
            {
                if (_headerInfos == null)
                {
                    _headerInfos = new HeaderInfo[maxHeaderInfos];
                }
                int i = _index;
                for (; ; )
                {
                    if (_headerInfos[i] == null)
                    {
                        break;
                    }
                    i = (i + 1) % maxHeaderInfos;
                    if (i == _index)
                    {
                        break;
                    }
                }
                _headerInfos[i] = headerInfoToReturn;
                _index = (i + 1) % maxHeaderInfos;
            }
        }
 
        internal class HeaderInfo : MessageHeaderInfo
        {
            private string _name;
            private string _ns;
            private string _actor;
            private bool _isReferenceParameter;
            private bool _mustUnderstand;
            private bool _relay;
 
            public HeaderInfo(XmlDictionaryReader reader, string actor, bool mustUnderstand, bool relay, bool isReferenceParameter)
            {
                _actor = actor;
                _mustUnderstand = mustUnderstand;
                _relay = relay;
                _isReferenceParameter = isReferenceParameter;
                _name = reader.LocalName;
                _ns = reader.NamespaceURI;
            }
 
            public override string Name
            {
                get { return _name; }
            }
 
            public override string Namespace
            {
                get { return _ns; }
            }
 
            public override bool IsReferenceParameter
            {
                get { return _isReferenceParameter; }
            }
 
            public override string Actor
            {
                get { return _actor; }
            }
 
            public override bool MustUnderstand
            {
                get { return _mustUnderstand; }
            }
 
            public override bool Relay
            {
                get { return _relay; }
            }
 
            public bool Matches(XmlDictionaryReader reader, string actor, bool mustUnderstand, bool relay, bool isRefParam)
            {
                return reader.IsStartElement(_name, _ns) &&
                    _actor == actor && _mustUnderstand == mustUnderstand && _relay == relay && _isReferenceParameter == isRefParam;
            }
        }
    }
 
    internal class UriCache
    {
        private const int MaxKeyLength = 128;
        private const int MaxEntries = 8;
        private Entry[] _entries;
        private int _count;
 
        public UriCache()
        {
            _entries = new Entry[MaxEntries];
        }
 
        public Uri CreateUri(string uriString)
        {
            Uri uri = Get(uriString);
            if (uri == null)
            {
                uri = new Uri(uriString);
                Set(uriString, uri);
            }
            return uri;
        }
 
        private Uri Get(string key)
        {
            if (key.Length > MaxKeyLength)
                return null;
            for (int i = _count - 1; i >= 0; i--)
                if (_entries[i].Key == key)
                    return _entries[i].Value;
            return null;
        }
 
        private void Set(string key, Uri value)
        {
            if (key.Length > MaxKeyLength)
                return;
            if (_count < _entries.Length)
            {
                _entries[_count++] = new Entry(key, value);
            }
            else
            {
                Array.Copy(_entries, 1, _entries, 0, _entries.Length - 1);
                _entries[_count - 1] = new Entry(key, value);
            }
        }
 
        internal struct Entry
        {
            private string _key;
            private Uri _value;
 
            public Entry(string key, Uri value)
            {
                _key = key;
                _value = value;
            }
 
            public string Key
            {
                get { return _key; }
            }
 
            public Uri Value
            {
                get { return _value; }
            }
        }
    }
}