2016-08-03 10:59:49 +00:00
|
|
|
//------------------------------------------------------------
|
|
|
|
// 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)
|
|
|
|
{
|
2017-08-21 15:34:15 +00:00
|
|
|
#pragma warning suppress 56506 // Microsoft, collection.version is never null
|
2016-08-03 10:59:49 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|