File: System\ServiceModel\Channels\MessageHeaders.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Channels
{
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Diagnostics;
    using System.Runtime;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.ServiceModel.Diagnostics;
    using System.ServiceModel.Dispatcher;
    using System.Xml;
 
    public sealed class MessageHeaders : IEnumerable<MessageHeaderInfo>
    {
        int collectionVersion;
        int headerCount;
        Header[] headers;
        MessageVersion version;
        IBufferedMessageData bufferedMessageData;
        UnderstoodHeaders understoodHeaders;
        const int InitialHeaderCount = 4;
        const int MaxRecycledArrayLength = 8;
        static XmlDictionaryString[] localNames;
 
        internal const string WildcardAction = "*";
 
        // The highest node and attribute counts reached by the BVTs were 1829 and 667 respectively.
        const int MaxBufferedHeaderNodes = 4096;
        const int MaxBufferedHeaderAttributes = 2048;
        int nodeCount = 0;
        int attrCount = 0;
        bool understoodHeadersModified;
 
        public MessageHeaders(MessageVersion version, int initialSize)
        {
            Init(version, initialSize);
        }
 
        public MessageHeaders(MessageVersion version)
            : this(version, InitialHeaderCount)
        {
        }
 
        internal MessageHeaders(MessageVersion version, XmlDictionaryReader reader, XmlAttributeHolder[] envelopeAttributes, XmlAttributeHolder[] headerAttributes, ref int maxSizeOfHeaders)
            : this(version)
        {
            if (maxSizeOfHeaders < 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new ArgumentOutOfRangeException("maxSizeOfHeaders", maxSizeOfHeaders,
                    SR.GetString(SR.ValueMustBeNonNegative)));
            }
 
            if (version == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version"));
            if (reader == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("reader"));
            if (reader.IsEmptyElement)
            {
                reader.Read();
                return;
            }
            XmlBuffer xmlBuffer = null;
            EnvelopeVersion envelopeVersion = version.Envelope;
            reader.ReadStartElement(XD.MessageDictionary.Header, envelopeVersion.DictionaryNamespace);
            while (reader.IsStartElement())
            {
                if (xmlBuffer == null)
                    xmlBuffer = new XmlBuffer(maxSizeOfHeaders);
                BufferedHeader bufferedHeader = new BufferedHeader(version, xmlBuffer, reader, envelopeAttributes, headerAttributes);
                HeaderProcessing processing = bufferedHeader.MustUnderstand ? HeaderProcessing.MustUnderstand : 0;
                HeaderKind kind = GetHeaderKind(bufferedHeader);
                if (kind != HeaderKind.Unknown)
                {
                    processing |= HeaderProcessing.Understood;
                    MessageHeaders.TraceUnderstood(bufferedHeader);
                }
                Header newHeader = new Header(kind, bufferedHeader, processing);
                AddHeader(newHeader);
            }
            if (xmlBuffer != null)
            {
                xmlBuffer.Close();
                maxSizeOfHeaders -= xmlBuffer.BufferSize;
            }
            reader.ReadEndElement();
            this.collectionVersion = 0;
        }
 
        internal MessageHeaders(MessageVersion version, XmlDictionaryReader reader, IBufferedMessageData bufferedMessageData, RecycledMessageState recycledMessageState, bool[] understoodHeaders, bool understoodHeadersModified)
        {
            this.headers = new Header[InitialHeaderCount];
            Init(version, reader, bufferedMessageData, recycledMessageState, understoodHeaders, understoodHeadersModified);
        }
 
        internal MessageHeaders(MessageVersion version, MessageHeaders headers, IBufferedMessageData bufferedMessageData)
        {
            this.version = version;
            this.bufferedMessageData = bufferedMessageData;
            this.headerCount = headers.headerCount;
            this.headers = new Header[headerCount];
            Array.Copy(headers.headers, this.headers, headerCount);
            this.collectionVersion = 0;
        }
 
        public MessageHeaders(MessageHeaders collection)
        {
            if (collection == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("collection");
 
            Init(collection.version, collection.headers.Length);
            CopyHeadersFrom(collection);
            this.collectionVersion = 0;
        }
 
        public string Action
        {
            get
            {
                int index = FindHeaderProperty(HeaderKind.Action);
                if (index < 0)
                    return null;
                ActionHeader actionHeader = headers[index].HeaderInfo as ActionHeader;
                if (actionHeader != null)
                    return actionHeader.Action;
                using (XmlDictionaryReader reader = GetReaderAtHeader(index))
                {
                    return ActionHeader.ReadHeaderValue(reader, version.Addressing);
                }
            }
            set
            {
                if (value != null)
                    SetActionHeader(ActionHeader.Create(value, version.Addressing));
                else
                    SetHeaderProperty(HeaderKind.Action, null);
            }
        }
 
        internal bool CanRecycle
        {
            get { return headers.Length <= MaxRecycledArrayLength; }
        }
 
        internal bool ContainsOnlyBufferedMessageHeaders
        {
            get { return (bufferedMessageData != null && collectionVersion == 0); }
        }
 
        internal int CollectionVersion
        {
            get { return collectionVersion; }
        }
 
        public int Count
        {
            get { return headerCount; }
        }
 
        public EndpointAddress FaultTo
        {
            get
            {
                int index = FindHeaderProperty(HeaderKind.FaultTo);
                if (index < 0)
                    return null;
                FaultToHeader faultToHeader = headers[index].HeaderInfo as FaultToHeader;
                if (faultToHeader != null)
                    return faultToHeader.FaultTo;
                using (XmlDictionaryReader reader = GetReaderAtHeader(index))
                {
                    return FaultToHeader.ReadHeaderValue(reader, version.Addressing);
                }
            }
            set
            {
                if (value != null)
                    SetFaultToHeader(FaultToHeader.Create(value, version.Addressing));
                else
                    SetHeaderProperty(HeaderKind.FaultTo, null);
            }
        }
 
        public EndpointAddress From
        {
            get
            {
                int index = FindHeaderProperty(HeaderKind.From);
                if (index < 0)
                    return null;
                FromHeader fromHeader = headers[index].HeaderInfo as FromHeader;
                if (fromHeader != null)
                    return fromHeader.From;
                using (XmlDictionaryReader reader = GetReaderAtHeader(index))
                {
                    return FromHeader.ReadHeaderValue(reader, version.Addressing);
                }
            }
            set
            {
                if (value != null)
                    SetFromHeader(FromHeader.Create(value, version.Addressing));
                else
                    SetHeaderProperty(HeaderKind.From, null);
            }
        }
 
        internal bool HasMustUnderstandBeenModified
        {
            get
            {
                if (understoodHeaders != null)
                {
                    return understoodHeaders.Modified;
                }
                else
                {
                    return this.understoodHeadersModified;
                }
            }
        }
 
        public UniqueId MessageId
        {
            get
            {
                int index = FindHeaderProperty(HeaderKind.MessageId);
                if (index < 0)
                    return null;
                MessageIDHeader messageIDHeader = headers[index].HeaderInfo as MessageIDHeader;
                if (messageIDHeader != null)
                    return messageIDHeader.MessageId;
                using (XmlDictionaryReader reader = GetReaderAtHeader(index))
                {
                    return MessageIDHeader.ReadHeaderValue(reader, version.Addressing);
                }
            }
            set
            {
                if (value != null)
                    SetMessageIDHeader(MessageIDHeader.Create(value, version.Addressing));
                else
                    SetHeaderProperty(HeaderKind.MessageId, null);
            }
        }
 
        public MessageVersion MessageVersion
        {
            get { return version; }
        }
 
        public UniqueId RelatesTo
        {
            get
            {
                return GetRelatesTo(RelatesToHeader.ReplyRelationshipType);
            }
            set
            {
                SetRelatesTo(RelatesToHeader.ReplyRelationshipType, value);
            }
        }
 
        public EndpointAddress ReplyTo
        {
            get
            {
                int index = FindHeaderProperty(HeaderKind.ReplyTo);
                if (index < 0)
                    return null;
                ReplyToHeader replyToHeader = headers[index].HeaderInfo as ReplyToHeader;
                if (replyToHeader != null)
                    return replyToHeader.ReplyTo;
                using (XmlDictionaryReader reader = GetReaderAtHeader(index))
                {
                    return ReplyToHeader.ReadHeaderValue(reader, version.Addressing);
                }
            }
            set
            {
                if (value != null)
                    SetReplyToHeader(ReplyToHeader.Create(value, version.Addressing));
                else
                    SetHeaderProperty(HeaderKind.ReplyTo, null);
            }
        }
 
        public Uri To
        {
            get
            {
                int index = FindHeaderProperty(HeaderKind.To);
                if (index < 0)
                    return null;
                ToHeader toHeader = headers[index].HeaderInfo as ToHeader;
                if (toHeader != null)
                    return toHeader.To;
                using (XmlDictionaryReader reader = GetReaderAtHeader(index))
                {
                    return ToHeader.ReadHeaderValue(reader, version.Addressing);
                }
            }
            set
            {
                if (value != null)
                    SetToHeader(ToHeader.Create(value, version.Addressing));
                else
                    SetHeaderProperty(HeaderKind.To, null);
            }
        }
 
        public UnderstoodHeaders UnderstoodHeaders
        {
            get
            {
                if (understoodHeaders == null)
                    understoodHeaders = new UnderstoodHeaders(this, understoodHeadersModified);
                return understoodHeaders;
            }
        }
 
        public MessageHeaderInfo this[int index]
        {
            get
            {
                if (index < 0 || index >= headerCount)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new ArgumentOutOfRangeException("index", index,
                        SR.GetString(SR.ValueMustBeInRange, 0, headerCount)));
                }
 
                return headers[index].HeaderInfo;
            }
        }
 
        public void Add(MessageHeader header)
        {
            Insert(headerCount, header);
        }
 
        internal void AddActionHeader(ActionHeader actionHeader)
        {
            Insert(headerCount, actionHeader, HeaderKind.Action);
        }
 
        internal void AddMessageIDHeader(MessageIDHeader messageIDHeader)
        {
            Insert(headerCount, messageIDHeader, HeaderKind.MessageId);
        }
 
        internal void AddRelatesToHeader(RelatesToHeader relatesToHeader)
        {
            Insert(headerCount, relatesToHeader, HeaderKind.RelatesTo);
        }
 
        internal void AddReplyToHeader(ReplyToHeader replyToHeader)
        {
            Insert(headerCount, replyToHeader, HeaderKind.ReplyTo);
        }
 
        internal void AddToHeader(ToHeader toHeader)
        {
            Insert(headerCount, toHeader, HeaderKind.To);
        }
 
        void Add(MessageHeader header, HeaderKind kind)
        {
            Insert(headerCount, header, kind);
        }
 
        void AddHeader(Header header)
        {
            InsertHeader(headerCount, header);
        }
 
        internal void AddUnderstood(int i)
        {
            headers[i].HeaderProcessing |= HeaderProcessing.Understood;
            MessageHeaders.TraceUnderstood(headers[i].HeaderInfo);
        }
 
        internal void AddUnderstood(MessageHeaderInfo headerInfo)
        {
            if (headerInfo == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("headerInfo"));
            for (int i = 0; i < headerCount; i++)
            {
                if ((object)headers[i].HeaderInfo == (object)headerInfo)
                {
                    if ((headers[i].HeaderProcessing & HeaderProcessing.Understood) != 0)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(
                            SR.GetString(SR.HeaderAlreadyUnderstood, headerInfo.Name, headerInfo.Namespace), "headerInfo"));
                    }
 
                    AddUnderstood(i);
                }
            }
        }
 
        void CaptureBufferedHeaders()
        {
            CaptureBufferedHeaders(-1);
        }
 
        void CaptureBufferedHeaders(int exceptIndex)
        {
            using (XmlDictionaryReader reader = GetBufferedMessageHeaderReaderAtHeaderContents(bufferedMessageData))
            {
                for (int i = 0; i < headerCount; i++)
                {
                    if (reader.NodeType != XmlNodeType.Element)
                    {
                        if (reader.MoveToContent() != XmlNodeType.Element)
                            break;
                    }
 
                    Header header = headers[i];
                    if (i == exceptIndex || header.HeaderType != HeaderType.BufferedMessageHeader)
                    {
                        reader.Skip();
                    }
                    else
                    {
                        headers[i] = new Header(header.HeaderKind, CaptureBufferedHeader(reader,
                            header.HeaderInfo), header.HeaderProcessing);
                    }
                }
            }
            bufferedMessageData = null;
        }
 
        BufferedHeader CaptureBufferedHeader(XmlDictionaryReader reader, MessageHeaderInfo headerInfo)
        {
            XmlBuffer buffer = new XmlBuffer(int.MaxValue);
            XmlDictionaryWriter writer = buffer.OpenSection(bufferedMessageData.Quotas);
            writer.WriteNode(reader, false);
            buffer.CloseSection();
            buffer.Close();
            return new BufferedHeader(version, buffer, 0, headerInfo);
        }
 
        BufferedHeader CaptureBufferedHeader(IBufferedMessageData bufferedMessageData, MessageHeaderInfo headerInfo, int bufferedMessageHeaderIndex)
        {
            XmlBuffer buffer = new XmlBuffer(int.MaxValue);
            XmlDictionaryWriter writer = buffer.OpenSection(bufferedMessageData.Quotas);
            WriteBufferedMessageHeader(bufferedMessageData, bufferedMessageHeaderIndex, writer);
            buffer.CloseSection();
            buffer.Close();
            return new BufferedHeader(version, buffer, 0, headerInfo);
        }
 
        BufferedHeader CaptureWriteableHeader(MessageHeader writeableHeader)
        {
            XmlBuffer buffer = new XmlBuffer(int.MaxValue);
            XmlDictionaryWriter writer = buffer.OpenSection(XmlDictionaryReaderQuotas.Max);
            writeableHeader.WriteHeader(writer, this.version);
            buffer.CloseSection();
            buffer.Close();
            return new BufferedHeader(version, buffer, 0, writeableHeader);
        }
 
        public void Clear()
        {
            for (int i = 0; i < headerCount; i++)
                headers[i] = new Header();
            headerCount = 0;
            collectionVersion++;
            bufferedMessageData = null;
        }
 
        public void CopyHeaderFrom(Message message, int headerIndex)
        {
            if (message == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("message"));
            CopyHeaderFrom(message.Headers, headerIndex);
        }
 
        public void CopyHeaderFrom(MessageHeaders collection, int headerIndex)
        {
            if (collection == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("collection");
            }
 
            if (collection.version != version)
            {
#pragma warning suppress 56506 // Microsoft, collection.version is never null
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.MessageHeaderVersionMismatch, collection.version.ToString(), version.ToString()), "collection"));
            }
 
            if (headerIndex < 0 || headerIndex >= collection.headerCount)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new ArgumentOutOfRangeException("headerIndex", headerIndex,
                    SR.GetString(SR.ValueMustBeInRange, 0, collection.headerCount)));
            }
            Header header = collection.headers[headerIndex];
            HeaderProcessing processing = header.HeaderInfo.MustUnderstand ? HeaderProcessing.MustUnderstand : 0;
            if ((header.HeaderProcessing & HeaderProcessing.Understood) != 0 || header.HeaderKind != HeaderKind.Unknown)
                processing |= HeaderProcessing.Understood;
            switch (header.HeaderType)
            {
                case HeaderType.BufferedMessageHeader:
                    AddHeader(new Header(header.HeaderKind, collection.CaptureBufferedHeader(collection.bufferedMessageData,
                        header.HeaderInfo, headerIndex), processing));
                    break;
                case HeaderType.ReadableHeader:
                    AddHeader(new Header(header.HeaderKind, header.ReadableHeader, processing));
                    break;
                case HeaderType.WriteableHeader:
                    AddHeader(new Header(header.HeaderKind, header.MessageHeader, processing));
                    break;
                default:
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidEnumValue, header.HeaderType)));
            }
        }
 
        public void CopyHeadersFrom(Message message)
        {
            if (message == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("message"));
            CopyHeadersFrom(message.Headers);
        }
 
        public void CopyHeadersFrom(MessageHeaders collection)
        {
            if (collection == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("collection"));
            for (int i = 0; i < collection.headerCount; i++)
                CopyHeaderFrom(collection, i);
        }
 
        public void CopyTo(MessageHeaderInfo[] array, int index)
        {
            if (array == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("array");
            }
 
            if (index < 0 || (index + headerCount) > array.Length)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new ArgumentOutOfRangeException("index", index,
                    SR.GetString(SR.ValueMustBeInRange, 0, array.Length - headerCount)));
            }
            for (int i = 0; i < headerCount; i++)
                array[i + index] = headers[i].HeaderInfo;
        }
 
        Exception CreateDuplicateHeaderException(HeaderKind kind)
        {
            string name;
            switch (kind)
            {
                case HeaderKind.Action:
                    name = AddressingStrings.Action;
                    break;
                case HeaderKind.FaultTo:
                    name = AddressingStrings.FaultTo;
                    break;
                case HeaderKind.From:
                    name = AddressingStrings.From;
                    break;
                case HeaderKind.MessageId:
                    name = AddressingStrings.MessageId;
                    break;
                case HeaderKind.ReplyTo:
                    name = AddressingStrings.ReplyTo;
                    break;
                case HeaderKind.To:
                    name = AddressingStrings.To;
                    break;
                default:
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidEnumValue, kind)));
            }
 
            return new MessageHeaderException(
                SR.GetString(SR.MultipleMessageHeaders, name, this.version.Addressing.Namespace),
                name,
                this.version.Addressing.Namespace,
                true);
        }
 
        public int FindHeader(string name, string ns)
        {
            if (name == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("name"));
            if (ns == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("ns"));
 
            if (ns == this.version.Addressing.Namespace)
            {
                return FindAddressingHeader(name, ns);
            }
            else
            {
                return FindNonAddressingHeader(name, ns, version.Envelope.UltimateDestinationActorValues);
            }
        }
 
        int FindAddressingHeader(string name, string ns)
        {
            int foundAt = -1;
            for (int i = 0; i < headerCount; i++)
            {
                if (headers[i].HeaderKind != HeaderKind.Unknown)
                {
                    MessageHeaderInfo info = headers[i].HeaderInfo;
                    if (info.Name == name && info.Namespace == ns)
                    {
                        if (foundAt >= 0)
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                                new MessageHeaderException(SR.GetString(SR.MultipleMessageHeaders, name, ns), name, ns, true));
                        }
                        foundAt = i;
                    }
                }
            }
            return foundAt;
        }
 
        int FindNonAddressingHeader(string name, string ns, string[] actors)
        {
            int foundAt = -1;
            for (int i = 0; i < headerCount; i++)
            {
                if (headers[i].HeaderKind == HeaderKind.Unknown)
                {
                    MessageHeaderInfo info = headers[i].HeaderInfo;
                    if (info.Name == name && info.Namespace == ns)
                    {
                        for (int j = 0; j < actors.Length; j++)
                        {
                            if (actors[j] == info.Actor)
                            {
                                if (foundAt >= 0)
                                {
                                    if (actors.Length == 1)
                                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageHeaderException(SR.GetString(SR.MultipleMessageHeadersWithActor, name, ns, actors[0]), name, ns, true));
                                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageHeaderException(SR.GetString(SR.MultipleMessageHeaders, name, ns), name, ns, true));
                                }
                                foundAt = i;
                            }
                        }
                    }
                }
            }
            return foundAt;
        }
 
        public int FindHeader(string name, string ns, params string[] actors)
        {
            if (name == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("name"));
            if (ns == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("ns"));
            if (actors == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("actors"));
            int foundAt = -1;
            for (int i = 0; i < headerCount; i++)
            {
                MessageHeaderInfo info = headers[i].HeaderInfo;
                if (info.Name == name && info.Namespace == ns)
                {
                    for (int j = 0; j < actors.Length; j++)
                    {
                        if (actors[j] == info.Actor)
                        {
                            if (foundAt >= 0)
                            {
                                if (actors.Length == 1)
                                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageHeaderException(SR.GetString(SR.MultipleMessageHeadersWithActor, name, ns, actors[0]), name, ns, true));
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageHeaderException(SR.GetString(SR.MultipleMessageHeaders, name, ns), name, ns, true));
                            }
                            foundAt = i;
                        }
                    }
                }
            }
            return foundAt;
        }
 
        int FindHeaderProperty(HeaderKind kind)
        {
            int index = -1;
            for (int i = 0; i < headerCount; i++)
            {
                if (headers[i].HeaderKind == kind)
                {
                    if (index >= 0)
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateDuplicateHeaderException(kind));
                    index = i;
                }
            }
            return index;
        }
 
        int FindRelatesTo(Uri relationshipType, out UniqueId messageId)
        {
            UniqueId foundValue = null;
            int foundIndex = -1;
            for (int i = 0; i < headerCount; i++)
            {
                if (headers[i].HeaderKind == HeaderKind.RelatesTo)
                {
                    Uri tempRelationship;
                    UniqueId tempValue;
                    GetRelatesToValues(i, out tempRelationship, out tempValue);
 
                    if (relationshipType == tempRelationship)
                    {
                        if (foundValue != null)
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                                new MessageHeaderException(
                                    SR.GetString(SR.MultipleRelatesToHeaders, relationshipType.AbsoluteUri),
                                    AddressingStrings.RelatesTo,
                                    this.version.Addressing.Namespace,
                                    true));
                        }
                        foundValue = tempValue;
                        foundIndex = i;
                    }
                }
            }
 
            messageId = foundValue;
            return foundIndex;
        }
 
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
 
        public IEnumerator<MessageHeaderInfo> GetEnumerator()
        {
            MessageHeaderInfo[] headers = new MessageHeaderInfo[headerCount];
            CopyTo(headers, 0);
            return GetEnumerator(headers);
        }
 
        IEnumerator<MessageHeaderInfo> GetEnumerator(MessageHeaderInfo[] headers)
        {
            IList<MessageHeaderInfo> list = Array.AsReadOnly<MessageHeaderInfo>(headers);
            return list.GetEnumerator();
        }
 
        internal IEnumerator<MessageHeaderInfo> GetUnderstoodEnumerator()
        {
            List<MessageHeaderInfo> understoodHeaders = new List<MessageHeaderInfo>();
 
            for (int i = 0; i < headerCount; i++)
            {
                if ((headers[i].HeaderProcessing & HeaderProcessing.Understood) != 0)
                {
                    understoodHeaders.Add(headers[i].HeaderInfo);
                }
            }
 
            return understoodHeaders.GetEnumerator();
        }
 
        static XmlDictionaryReader GetBufferedMessageHeaderReaderAtHeaderContents(IBufferedMessageData bufferedMessageData)
        {
            XmlDictionaryReader reader = bufferedMessageData.GetMessageReader();
            if (reader.NodeType == XmlNodeType.Element)
                reader.Read();
            else
                reader.ReadStartElement();
            if (reader.NodeType == XmlNodeType.Element)
                reader.Read();
            else
                reader.ReadStartElement();
            return reader;
        }
 
        XmlDictionaryReader GetBufferedMessageHeaderReader(IBufferedMessageData bufferedMessageData, int bufferedMessageHeaderIndex)
        {
            // Check if we need to change representations
            if (this.nodeCount > MaxBufferedHeaderNodes || this.attrCount > MaxBufferedHeaderAttributes)
            {
                CaptureBufferedHeaders();
                return headers[bufferedMessageHeaderIndex].ReadableHeader.GetHeaderReader();
            }
 
            XmlDictionaryReader reader = GetBufferedMessageHeaderReaderAtHeaderContents(bufferedMessageData);
            for (;;)
            {
                if (reader.NodeType != XmlNodeType.Element)
                    reader.MoveToContent();
                if (bufferedMessageHeaderIndex == 0)
                    break;
                Skip(reader);
                bufferedMessageHeaderIndex--;
            }
 
            return reader;
        }
 
        void Skip(XmlDictionaryReader reader)
        {
            if (reader.MoveToContent() == XmlNodeType.Element && !reader.IsEmptyElement)
            {
                int depth = reader.Depth;
                do
                {
                    this.attrCount += reader.AttributeCount;
                    this.nodeCount++;
                } while (reader.Read() && depth < reader.Depth);
 
                // consume end tag
                if (reader.NodeType == XmlNodeType.EndElement)
                {
                    this.nodeCount++;
                    reader.Read();
                }
            }
            else
            {
                this.attrCount += reader.AttributeCount;
                this.nodeCount++;
                reader.Read();
            }
        }
 
        public T GetHeader<T>(string name, string ns)
        {
            return GetHeader<T>(name, ns, DataContractSerializerDefaults.CreateSerializer(typeof(T), name, ns, int.MaxValue/*maxItems*/));
        }
 
        public T GetHeader<T>(string name, string ns, params string[] actors)
        {
            int index = FindHeader(name, ns, actors);
            if (index < 0)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageHeaderException(SR.GetString(SR.HeaderNotFound, name, ns), name, ns));
            return GetHeader<T>(index);
 
        }
 
        public T GetHeader<T>(string name, string ns, XmlObjectSerializer serializer)
        {
            if (serializer == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("serializer"));
            int index = FindHeader(name, ns);
            if (index < 0)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageHeaderException(SR.GetString(SR.HeaderNotFound, name, ns), name, ns));
            return GetHeader<T>(index, serializer);
        }
 
        public T GetHeader<T>(int index)
        {
            if (index < 0 || index >= headerCount)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new ArgumentOutOfRangeException("index", index,
                    SR.GetString(SR.ValueMustBeInRange, 0, headerCount)));
            }
 
            MessageHeaderInfo headerInfo = headers[index].HeaderInfo;
            return GetHeader<T>(index, DataContractSerializerDefaults.CreateSerializer(typeof(T), headerInfo.Name, headerInfo.Namespace, int.MaxValue/*maxItems*/));
        }
 
        public T GetHeader<T>(int index, XmlObjectSerializer serializer)
        {
            if (serializer == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("serializer"));
            using (XmlDictionaryReader reader = GetReaderAtHeader(index))
            {
                return (T)serializer.ReadObject(reader);
            }
        }
 
        HeaderKind GetHeaderKind(MessageHeaderInfo headerInfo)
        {
            HeaderKind headerKind = HeaderKind.Unknown;
 
            if (headerInfo.Namespace == this.version.Addressing.Namespace)
            {
                if (version.Envelope.IsUltimateDestinationActor(headerInfo.Actor))
                {
                    string name = headerInfo.Name;
                    if (name.Length > 0)
                    {
                        switch (name[0])
                        {
                            case 'A':
                                if (name == AddressingStrings.Action)
                                {
                                    headerKind = HeaderKind.Action;
                                }
                                break;
                            case 'F':
                                if (name == AddressingStrings.From)
                                {
                                    headerKind = HeaderKind.From;
                                }
                                else if (name == AddressingStrings.FaultTo)
                                {
                                    headerKind = HeaderKind.FaultTo;
                                }
                                break;
                            case 'M':
                                if (name == AddressingStrings.MessageId)
                                {
                                    headerKind = HeaderKind.MessageId;
                                }
                                break;
                            case 'R':
                                if (name == AddressingStrings.ReplyTo)
                                {
                                    headerKind = HeaderKind.ReplyTo;
                                }
                                else if (name == AddressingStrings.RelatesTo)
                                {
                                    headerKind = HeaderKind.RelatesTo;
                                }
                                break;
                            case 'T':
                                if (name == AddressingStrings.To)
                                {
                                    headerKind = HeaderKind.To;
                                }
                                break;
                        }
                    }
                }
            }
 
            ValidateHeaderKind(headerKind);
            return headerKind;
        }
 
        void ValidateHeaderKind(HeaderKind headerKind)
        {
            if (this.version.Envelope == EnvelopeVersion.None)
            {
                if (headerKind != HeaderKind.Action && headerKind != HeaderKind.To)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new InvalidOperationException(SR.GetString(SR.HeadersCannotBeAddedToEnvelopeVersion, this.version.Envelope)));
                }
            }
 
            if (this.version.Addressing == AddressingVersion.None)
            {
                if (headerKind != HeaderKind.Unknown && headerKind != HeaderKind.Action && headerKind != HeaderKind.To)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new InvalidOperationException(SR.GetString(SR.AddressingHeadersCannotBeAddedToAddressingVersion, this.version.Addressing)));
                }
            }
        }
 
        public XmlDictionaryReader GetReaderAtHeader(int headerIndex)
        {
            if (headerIndex < 0 || headerIndex >= headerCount)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new ArgumentOutOfRangeException("headerIndex", headerIndex,
                    SR.GetString(SR.ValueMustBeInRange, 0, headerCount)));
            }
 
            switch (headers[headerIndex].HeaderType)
            {
                case HeaderType.ReadableHeader:
                    return headers[headerIndex].ReadableHeader.GetHeaderReader();
                case HeaderType.WriteableHeader:
                    MessageHeader writeableHeader = headers[headerIndex].MessageHeader;
                    BufferedHeader bufferedHeader = CaptureWriteableHeader(writeableHeader);
                    headers[headerIndex] = new Header(headers[headerIndex].HeaderKind, bufferedHeader, headers[headerIndex].HeaderProcessing);
                    collectionVersion++;
                    return bufferedHeader.GetHeaderReader();
                case HeaderType.BufferedMessageHeader:
                    return GetBufferedMessageHeaderReader(bufferedMessageData, headerIndex);
                default:
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidEnumValue, headers[headerIndex].HeaderType)));
            }
        }
 
        internal UniqueId GetRelatesTo(Uri relationshipType)
        {
            if (relationshipType == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("relationshipType"));
 
            UniqueId messageId;
            FindRelatesTo(relationshipType, out messageId);
            return messageId;
        }
 
        void GetRelatesToValues(int index, out Uri relationshipType, out UniqueId messageId)
        {
            RelatesToHeader relatesToHeader = headers[index].HeaderInfo as RelatesToHeader;
            if (relatesToHeader != null)
            {
                relationshipType = relatesToHeader.RelationshipType;
                messageId = relatesToHeader.UniqueId;
            }
            else
            {
                using (XmlDictionaryReader reader = GetReaderAtHeader(index))
                {
                    RelatesToHeader.ReadHeaderValue(reader, version.Addressing, out relationshipType, out messageId);
                }
            }
        }
 
        internal string[] GetHeaderAttributes(string localName, string ns)
        {
            string[] attrs = null;
 
            if (ContainsOnlyBufferedMessageHeaders)
            {
                XmlDictionaryReader reader = bufferedMessageData.GetMessageReader();
                reader.ReadStartElement(); // Envelope
                reader.ReadStartElement(); // Header
                for (int index = 0; reader.IsStartElement(); index++)
                {
                    string value = reader.GetAttribute(localName, ns);
                    if (value != null)
                    {
                        if (attrs == null)
                            attrs = new string[headerCount];
                        attrs[index] = value;
                    }
                    if (index == headerCount - 1)
                        break;
                    reader.Skip();
                }
                reader.Close();
            }
            else
            {
                for (int index = 0; index < headerCount; index++)
                {
                    if (headers[index].HeaderType != HeaderType.WriteableHeader)
                    {
                        using (XmlDictionaryReader reader = GetReaderAtHeader(index))
                        {
                            string value = reader.GetAttribute(localName, ns);
                            if (value != null)
                            {
                                if (attrs == null)
                                    attrs = new string[headerCount];
                                attrs[index] = value;
                            }
                        }
                    }
                }
            }
 
            return attrs;
        }
 
        internal MessageHeader GetMessageHeader(int index)
        {
            if (index < 0 || index >= headerCount)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new ArgumentOutOfRangeException("headerIndex", index,
                    SR.GetString(SR.ValueMustBeInRange, 0, headerCount)));
            }
            MessageHeader messageHeader;
            switch (headers[index].HeaderType)
            {
                case HeaderType.WriteableHeader:
                case HeaderType.ReadableHeader:
                    return headers[index].MessageHeader;
                case HeaderType.BufferedMessageHeader:
                    messageHeader = CaptureBufferedHeader(bufferedMessageData, headers[index].HeaderInfo, index);
                    headers[index] = new Header(headers[index].HeaderKind, messageHeader, headers[index].HeaderProcessing);
                    collectionVersion++;
                    return messageHeader;
                default:
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidEnumValue, headers[index].HeaderType)));
            }
        }
 
        internal Collection<MessageHeaderInfo> GetHeadersNotUnderstood()
        {
            Collection<MessageHeaderInfo> notUnderstoodHeaders = null;
 
            for (int headerIndex = 0; headerIndex < headerCount; headerIndex++)
            {
                if (headers[headerIndex].HeaderProcessing == HeaderProcessing.MustUnderstand)
                {
                    if (notUnderstoodHeaders == null)
                        notUnderstoodHeaders = new Collection<MessageHeaderInfo>();
 
                    MessageHeaderInfo headerInfo = headers[headerIndex].HeaderInfo;
                    if (DiagnosticUtility.ShouldTraceWarning)
                    {
                        TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.DidNotUnderstandMessageHeader,
                            SR.GetString(SR.TraceCodeDidNotUnderstandMessageHeader),
                            new MessageHeaderInfoTraceRecord(headerInfo), null, null);
                    }
 
                    notUnderstoodHeaders.Add(headerInfo);
                }
            }
 
            return notUnderstoodHeaders;
        }
 
        public bool HaveMandatoryHeadersBeenUnderstood()
        {
            return HaveMandatoryHeadersBeenUnderstood(version.Envelope.MustUnderstandActorValues);
        }
 
        public bool HaveMandatoryHeadersBeenUnderstood(params string[] actors)
        {
            if (actors == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("actors"));
 
            for (int headerIndex = 0; headerIndex < headerCount; headerIndex++)
            {
                if (headers[headerIndex].HeaderProcessing == HeaderProcessing.MustUnderstand)
                {
                    for (int actorIndex = 0; actorIndex < actors.Length; ++actorIndex)
                    {
                        if (headers[headerIndex].HeaderInfo.Actor == actors[actorIndex])
                        {
                            return false;
                        }
                    }
                }
            }
 
            return true;
        }
 
        internal void Init(MessageVersion version, int initialSize)
        {
            this.nodeCount = 0;
            this.attrCount = 0;
            if (initialSize < 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new ArgumentOutOfRangeException("initialSize", initialSize,
                    SR.GetString(SR.ValueMustBeNonNegative)));
            }
 
            if (version == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("version");
            }
 
            this.version = version;
            headers = new Header[initialSize];
        }
 
        internal void Init(MessageVersion version)
        {
            this.nodeCount = 0;
            this.attrCount = 0;
            this.version = version;
            this.collectionVersion = 0;
        }
 
        internal void Init(MessageVersion version, XmlDictionaryReader reader, IBufferedMessageData bufferedMessageData, RecycledMessageState recycledMessageState, bool[] understoodHeaders, bool understoodHeadersModified)
        {
            this.nodeCount = 0;
            this.attrCount = 0;
            this.version = version;
            this.bufferedMessageData = bufferedMessageData;
 
            if (version.Envelope != EnvelopeVersion.None)
            {
                this.understoodHeadersModified = (understoodHeaders != null) && understoodHeadersModified;
                if (reader.IsEmptyElement)
                {
                    reader.Read();
                    return;
                }
                EnvelopeVersion envelopeVersion = version.Envelope;
                Fx.Assert(reader.IsStartElement(XD.MessageDictionary.Header, envelopeVersion.DictionaryNamespace), "");
                reader.ReadStartElement();
 
                AddressingDictionary dictionary = XD.AddressingDictionary;
 
                if (localNames == null)
                {
                    XmlDictionaryString[] strings = new XmlDictionaryString[7];
                    strings[(int)HeaderKind.To] = dictionary.To;
                    strings[(int)HeaderKind.Action] = dictionary.Action;
                    strings[(int)HeaderKind.MessageId] = dictionary.MessageId;
                    strings[(int)HeaderKind.RelatesTo] = dictionary.RelatesTo;
                    strings[(int)HeaderKind.ReplyTo] = dictionary.ReplyTo;
                    strings[(int)HeaderKind.From] = dictionary.From;
                    strings[(int)HeaderKind.FaultTo] = dictionary.FaultTo;
                    System.Threading.Thread.MemoryBarrier();
                    localNames = strings;
                }
 
 
                int i = 0;
                while (reader.IsStartElement())
                {
                    ReadBufferedHeader(reader, recycledMessageState, localNames, (understoodHeaders == null) ? false : understoodHeaders[i++]);
                }
 
                reader.ReadEndElement();
            }
            this.collectionVersion = 0;
        }
 
        public void Insert(int headerIndex, MessageHeader header)
        {
            if (header == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("header"));
            if (!header.IsMessageVersionSupported(this.version))
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.MessageHeaderVersionNotSupported,
                    header.GetType().FullName, this.version.Envelope.ToString()), "header"));
            Insert(headerIndex, header, GetHeaderKind(header));
        }
 
        void Insert(int headerIndex, MessageHeader header, HeaderKind kind)
        {
            ReadableMessageHeader readableMessageHeader = header as ReadableMessageHeader;
            HeaderProcessing processing = header.MustUnderstand ? HeaderProcessing.MustUnderstand : 0;
            if (kind != HeaderKind.Unknown)
                processing |= HeaderProcessing.Understood;
            if (readableMessageHeader != null)
                InsertHeader(headerIndex, new Header(kind, readableMessageHeader, processing));
            else
                InsertHeader(headerIndex, new Header(kind, header, processing));
        }
 
        void InsertHeader(int headerIndex, Header header)
        {
            ValidateHeaderKind(header.HeaderKind);
 
            if (headerIndex < 0 || headerIndex > headerCount)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new ArgumentOutOfRangeException("headerIndex", headerIndex,
                    SR.GetString(SR.ValueMustBeInRange, 0, headerCount)));
            }
 
            if (headerCount == headers.Length)
            {
                if (headers.Length == 0)
                {
                    headers = new Header[1];
                }
                else
                {
                    Header[] newHeaders = new Header[headers.Length * 2];
                    headers.CopyTo(newHeaders, 0);
                    headers = newHeaders;
                }
            }
            if (headerIndex < headerCount)
            {
                if (bufferedMessageData != null)
                {
                    for (int i = headerIndex; i < headerCount; i++)
                    {
                        if (headers[i].HeaderType == HeaderType.BufferedMessageHeader)
                        {
                            CaptureBufferedHeaders();
                            break;
                        }
                    }
                }
                Array.Copy(headers, headerIndex, headers, headerIndex + 1, headerCount - headerIndex);
            }
            headers[headerIndex] = header;
            headerCount++;
            collectionVersion++;
        }
 
        internal bool IsUnderstood(int i)
        {
            return (headers[i].HeaderProcessing & HeaderProcessing.Understood) != 0;
        }
 
        internal bool IsUnderstood(MessageHeaderInfo headerInfo)
        {
            if (headerInfo == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("headerInfo"));
            for (int i = 0; i < headerCount; i++)
            {
                if ((object)headers[i].HeaderInfo == (object)headerInfo)
                {
                    if (IsUnderstood(i))
                        return true;
                }
            }
 
            return false;
        }
 
        void ReadBufferedHeader(XmlDictionaryReader reader, RecycledMessageState recycledMessageState, XmlDictionaryString[] localNames, bool understood)
        {
            string actor;
            bool mustUnderstand;
            bool relay;
            bool isRefParam;
 
            if (this.version.Addressing == AddressingVersion.None && reader.NamespaceURI == AddressingVersion.None.Namespace)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new InvalidOperationException(SR.GetString(SR.AddressingHeadersCannotBeAddedToAddressingVersion, this.version.Addressing)));
            }
 
            MessageHeader.GetHeaderAttributes(reader, version, out actor, out mustUnderstand, out relay, out isRefParam);
 
            HeaderKind kind = HeaderKind.Unknown;
            MessageHeaderInfo info = null;
 
            if (version.Envelope.IsUltimateDestinationActor(actor))
            {
                Fx.Assert(version.Addressing.DictionaryNamespace != null, "non-None Addressing requires a non-null DictionaryNamespace");
                kind = (HeaderKind)reader.IndexOfLocalName(localNames, version.Addressing.DictionaryNamespace);
                switch (kind)
                {
                    case HeaderKind.To:
                        info = ToHeader.ReadHeader(reader, version.Addressing, recycledMessageState.UriCache, actor, mustUnderstand, relay);
                        break;
                    case HeaderKind.Action:
                        info = ActionHeader.ReadHeader(reader, version.Addressing, actor, mustUnderstand, relay);
                        break;
                    case HeaderKind.MessageId:
                        info = MessageIDHeader.ReadHeader(reader, version.Addressing, actor, mustUnderstand, relay);
                        break;
                    case HeaderKind.RelatesTo:
                        info = RelatesToHeader.ReadHeader(reader, version.Addressing, actor, mustUnderstand, relay);
                        break;
                    case HeaderKind.ReplyTo:
                        info = ReplyToHeader.ReadHeader(reader, version.Addressing, actor, mustUnderstand, relay);
                        break;
                    case HeaderKind.From:
                        info = FromHeader.ReadHeader(reader, version.Addressing, actor, mustUnderstand, relay);
                        break;
                    case HeaderKind.FaultTo:
                        info = FaultToHeader.ReadHeader(reader, version.Addressing, actor, mustUnderstand, relay);
                        break;
                    default:
                        kind = HeaderKind.Unknown;
                        break;
                }
            }
 
            if (info == null)
            {
                info = recycledMessageState.HeaderInfoCache.TakeHeaderInfo(reader, actor, mustUnderstand, relay, isRefParam);
                reader.Skip();
            }
 
            HeaderProcessing processing = mustUnderstand ? HeaderProcessing.MustUnderstand : 0;
            if (kind != HeaderKind.Unknown || understood)
            {
                processing |= HeaderProcessing.Understood;
                MessageHeaders.TraceUnderstood(info);
            }
            AddHeader(new Header(kind, info, processing));
        }
 
        internal void Recycle(HeaderInfoCache headerInfoCache)
        {
            for (int i = 0; i < headerCount; i++)
            {
                if (headers[i].HeaderKind == HeaderKind.Unknown)
                {
                    headerInfoCache.ReturnHeaderInfo(headers[i].HeaderInfo);
                }
            }
            Clear();
            collectionVersion = 0;
            if (understoodHeaders != null)
            {
                understoodHeaders.Modified = false;
            }
        }
 
        internal void RemoveUnderstood(MessageHeaderInfo headerInfo)
        {
            if (headerInfo == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("headerInfo"));
            for (int i = 0; i < headerCount; i++)
            {
                if ((object)headers[i].HeaderInfo == (object)headerInfo)
                {
                    if ((headers[i].HeaderProcessing & HeaderProcessing.Understood) == 0)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(
                            SR.GetString(SR.HeaderAlreadyNotUnderstood, headerInfo.Name, headerInfo.Namespace), "headerInfo"));
                    }
 
                    headers[i].HeaderProcessing &= ~HeaderProcessing.Understood;
                }
            }
        }
 
        public void RemoveAll(string name, string ns)
        {
            if (name == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("name"));
            if (ns == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("ns"));
            for (int i = headerCount - 1; i >= 0; i--)
            {
                MessageHeaderInfo info = headers[i].HeaderInfo;
                if (info.Name == name && info.Namespace == ns)
                {
                    RemoveAt(i);
                }
            }
        }
 
        public void RemoveAt(int headerIndex)
        {
            if (headerIndex < 0 || headerIndex >= headerCount)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new ArgumentOutOfRangeException("headerIndex", headerIndex,
                    SR.GetString(SR.ValueMustBeInRange, 0, headerCount)));
            }
            if (bufferedMessageData != null && headers[headerIndex].HeaderType == HeaderType.BufferedMessageHeader)
                CaptureBufferedHeaders(headerIndex);
            Array.Copy(headers, headerIndex + 1, headers, headerIndex, headerCount - headerIndex - 1);
            headers[--headerCount] = new Header();
            collectionVersion++;
        }
 
        internal void ReplaceAt(int headerIndex, MessageHeader header)
        {
            if (headerIndex < 0 || headerIndex >= headerCount)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new ArgumentOutOfRangeException("headerIndex", headerIndex,
                    SR.GetString(SR.ValueMustBeInRange, 0, headerCount)));
            }
 
            if (header == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("header");
            }
 
            ReplaceAt(headerIndex, header, GetHeaderKind(header));
        }
 
        void ReplaceAt(int headerIndex, MessageHeader header, HeaderKind kind)
        {
            HeaderProcessing processing = header.MustUnderstand ? HeaderProcessing.MustUnderstand : 0;
            if (kind != HeaderKind.Unknown)
                processing |= HeaderProcessing.Understood;
            ReadableMessageHeader readableMessageHeader = header as ReadableMessageHeader;
            if (readableMessageHeader != null)
                headers[headerIndex] = new Header(kind, readableMessageHeader, processing);
            else
                headers[headerIndex] = new Header(kind, header, processing);
            collectionVersion++;
        }
 
        public void SetAction(XmlDictionaryString action)
        {
            if (action == null)
                SetHeaderProperty(HeaderKind.Action, null);
            else
                SetActionHeader(ActionHeader.Create(action, version.Addressing));
        }
 
        internal void SetActionHeader(ActionHeader actionHeader)
        {
            SetHeaderProperty(HeaderKind.Action, actionHeader);
        }
 
        internal void SetFaultToHeader(FaultToHeader faultToHeader)
        {
            SetHeaderProperty(HeaderKind.FaultTo, faultToHeader);
        }
 
        internal void SetFromHeader(FromHeader fromHeader)
        {
            SetHeaderProperty(HeaderKind.From, fromHeader);
        }
 
        internal void SetMessageIDHeader(MessageIDHeader messageIDHeader)
        {
            SetHeaderProperty(HeaderKind.MessageId, messageIDHeader);
        }
 
        internal void SetRelatesTo(Uri relationshipType, UniqueId messageId)
        {
            if (relationshipType == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("relationshipType");
            }
 
            RelatesToHeader relatesToHeader;
            if (!object.ReferenceEquals(messageId, null))
            {
                relatesToHeader = RelatesToHeader.Create(messageId, version.Addressing, relationshipType);
            }
            else
            {
                relatesToHeader = null;
            }
 
            SetRelatesTo(RelatesToHeader.ReplyRelationshipType, relatesToHeader);
        }
 
        void SetRelatesTo(Uri relationshipType, RelatesToHeader relatesToHeader)
        {
            UniqueId previousUniqueId;
            int index = FindRelatesTo(relationshipType, out previousUniqueId);
            if (index >= 0)
            {
                if (relatesToHeader == null)
                {
                    RemoveAt(index);
                }
                else
                {
                    ReplaceAt(index, relatesToHeader, HeaderKind.RelatesTo);
                }
            }
            else if (relatesToHeader != null)
            {
                Add(relatesToHeader, HeaderKind.RelatesTo);
            }
        }
 
        internal void SetReplyToHeader(ReplyToHeader replyToHeader)
        {
            SetHeaderProperty(HeaderKind.ReplyTo, replyToHeader);
        }
 
        internal void SetToHeader(ToHeader toHeader)
        {
            SetHeaderProperty(HeaderKind.To, toHeader);
        }
 
        void SetHeaderProperty(HeaderKind kind, MessageHeader header)
        {
            int index = FindHeaderProperty(kind);
            if (index >= 0)
            {
                if (header == null)
                {
                    RemoveAt(index);
                }
                else
                {
                    ReplaceAt(index, header, kind);
                }
            }
            else if (header != null)
            {
                Add(header, kind);
            }
        }
 
        public void WriteHeader(int headerIndex, XmlWriter writer)
        {
            WriteHeader(headerIndex, XmlDictionaryWriter.CreateDictionaryWriter(writer));
        }
 
        public void WriteHeader(int headerIndex, XmlDictionaryWriter writer)
        {
            WriteStartHeader(headerIndex, writer);
            WriteHeaderContents(headerIndex, writer);
            writer.WriteEndElement();
        }
 
        public void WriteStartHeader(int headerIndex, XmlWriter writer)
        {
            WriteStartHeader(headerIndex, XmlDictionaryWriter.CreateDictionaryWriter(writer));
        }
 
        public void WriteStartHeader(int headerIndex, XmlDictionaryWriter writer)
        {
            if (writer == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
            }
 
            if (headerIndex < 0 || headerIndex >= headerCount)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new ArgumentOutOfRangeException("headerIndex", headerIndex,
                    SR.GetString(SR.ValueMustBeInRange, 0, headerCount)));
            }
            switch (headers[headerIndex].HeaderType)
            {
                case HeaderType.ReadableHeader:
                case HeaderType.WriteableHeader:
                    headers[headerIndex].MessageHeader.WriteStartHeader(writer, this.version);
                    break;
                case HeaderType.BufferedMessageHeader:
                    WriteStartBufferedMessageHeader(bufferedMessageData, headerIndex, writer);
                    break;
                default:
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidEnumValue, headers[headerIndex].HeaderType)));
            }
        }
 
        public void WriteHeaderContents(int headerIndex, XmlWriter writer)
        {
            WriteHeaderContents(headerIndex, XmlDictionaryWriter.CreateDictionaryWriter(writer));
        }
 
        public void WriteHeaderContents(int headerIndex, XmlDictionaryWriter writer)
        {
            if (writer == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
            }
 
            if (headerIndex < 0 || headerIndex >= headerCount)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new ArgumentOutOfRangeException("headerIndex", headerIndex,
                    SR.GetString(SR.ValueMustBeInRange, 0, headerCount)));
            }
            switch (headers[headerIndex].HeaderType)
            {
                case HeaderType.ReadableHeader:
                case HeaderType.WriteableHeader:
                    headers[headerIndex].MessageHeader.WriteHeaderContents(writer, this.version);
                    break;
                case HeaderType.BufferedMessageHeader:
                    WriteBufferedMessageHeaderContents(bufferedMessageData, headerIndex, writer);
                    break;
                default:
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidEnumValue, headers[headerIndex].HeaderType)));
            }
        }
 
        static void TraceUnderstood(MessageHeaderInfo info)
        {
            if (DiagnosticUtility.ShouldTraceVerbose)
            {
                TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.UnderstoodMessageHeader,
                    SR.GetString(SR.TraceCodeUnderstoodMessageHeader),
                    new MessageHeaderInfoTraceRecord(info), null, null);
            }
        }
 
        void WriteBufferedMessageHeader(IBufferedMessageData bufferedMessageData, int bufferedMessageHeaderIndex, XmlWriter writer)
        {
            using (XmlReader reader = GetBufferedMessageHeaderReader(bufferedMessageData, bufferedMessageHeaderIndex))
            {
                writer.WriteNode(reader, false);
            }
        }
 
        void WriteStartBufferedMessageHeader(IBufferedMessageData bufferedMessageData, int bufferedMessageHeaderIndex, XmlWriter writer)
        {
            using (XmlReader reader = GetBufferedMessageHeaderReader(bufferedMessageData, bufferedMessageHeaderIndex))
            {
                writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
                writer.WriteAttributes(reader, false);
            }
        }
 
        void WriteBufferedMessageHeaderContents(IBufferedMessageData bufferedMessageData, int bufferedMessageHeaderIndex, XmlWriter writer)
        {
            using (XmlReader reader = GetBufferedMessageHeaderReader(bufferedMessageData, bufferedMessageHeaderIndex))
            {
                if (!reader.IsEmptyElement)
                {
                    reader.ReadStartElement();
                    while (reader.NodeType != XmlNodeType.EndElement)
                    {
                        writer.WriteNode(reader, false);
                    }
                    reader.ReadEndElement();
                }
            }
        }
 
        enum HeaderType : byte
        {
            Invalid,
            ReadableHeader,
            BufferedMessageHeader,
            WriteableHeader
        }
 
        enum HeaderKind : byte
        {
            Action,
            FaultTo,
            From,
            MessageId,
            ReplyTo,
            RelatesTo,
            To,
            Unknown,
        }
 
        [Flags]
        enum HeaderProcessing : byte
        {
            MustUnderstand = 0x1,
            Understood = 0x2,
        }
 
        struct Header
        {
            HeaderType type;
            HeaderKind kind;
            HeaderProcessing processing;
            MessageHeaderInfo info;
 
            public Header(HeaderKind kind, MessageHeaderInfo info, HeaderProcessing processing)
            {
                this.kind = kind;
                this.type = HeaderType.BufferedMessageHeader;
                this.info = info;
                this.processing = processing;
            }
 
            public Header(HeaderKind kind, ReadableMessageHeader readableHeader, HeaderProcessing processing)
            {
                this.kind = kind;
                this.type = HeaderType.ReadableHeader;
                this.info = readableHeader;
                this.processing = processing;
            }
 
            public Header(HeaderKind kind, MessageHeader header, HeaderProcessing processing)
            {
                this.kind = kind;
                this.type = HeaderType.WriteableHeader;
                this.info = header;
                this.processing = processing;
            }
 
            public HeaderType HeaderType
            {
                get { return type; }
            }
 
            public HeaderKind HeaderKind
            {
                get { return kind; }
            }
 
            public MessageHeaderInfo HeaderInfo
            {
                get { return info; }
            }
 
            public MessageHeader MessageHeader
            {
                get
                {
                    Fx.Assert(type == HeaderType.WriteableHeader || type == HeaderType.ReadableHeader, "");
                    return (MessageHeader)info;
                }
            }
 
            public HeaderProcessing HeaderProcessing
            {
                get { return processing; }
                set { processing = value; }
            }
 
            public ReadableMessageHeader ReadableHeader
            {
                get
                {
                    Fx.Assert(type == HeaderType.ReadableHeader, "");
                    return (ReadableMessageHeader)info;
                }
            }
        }
    }
}