//------------------------------------------------------------ // 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 { 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 // [....], 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 GetEnumerator() { MessageHeaderInfo[] headers = new MessageHeaderInfo[headerCount]; CopyTo(headers, 0); return GetEnumerator(headers); } IEnumerator GetEnumerator(MessageHeaderInfo[] headers) { IList list = Array.AsReadOnly(headers); return list.GetEnumerator(); } internal IEnumerator GetUnderstoodEnumerator() { List understoodHeaders = new List(); 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(string name, string ns) { return GetHeader(name, ns, DataContractSerializerDefaults.CreateSerializer(typeof(T), name, ns, int.MaxValue/*maxItems*/)); } public T GetHeader(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(index); } public T GetHeader(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(index, serializer); } public T GetHeader(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(index, DataContractSerializerDefaults.CreateSerializer(typeof(T), headerInfo.Name, headerInfo.Namespace, int.MaxValue/*maxItems*/)); } public T GetHeader(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 GetHeadersNotUnderstood() { Collection notUnderstoodHeaders = null; for (int headerIndex = 0; headerIndex < headerCount; headerIndex++) { if (headers[headerIndex].HeaderProcessing == HeaderProcessing.MustUnderstand) { if (notUnderstoodHeaders == null) notUnderstoodHeaders = new Collection(); 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; } } } } }