//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ namespace System.ServiceModel.Channels { using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Runtime; using System.Runtime.Serialization; using System.ServiceModel; using System.ServiceModel.Diagnostics; using System.ServiceModel.Dispatcher; using System.Threading; using System.Xml; public abstract class Message : IDisposable { MessageState state; SeekableMessageNavigator messageNavigator; internal const int InitialBufferSize = 1024; public abstract MessageHeaders Headers { get; } // must never return null protected bool IsDisposed { get { return state == MessageState.Closed; } } public virtual bool IsFault { get { if (IsDisposed) #pragma warning suppress 56503 // Microsoft, Invalid State after dispose throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this); return false; } } public virtual bool IsEmpty { get { if (IsDisposed) #pragma warning suppress 56503 // Microsoft, Invalid State after dispose throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this); return false; } } public abstract MessageProperties Properties { get; } public abstract MessageVersion Version { get; } // must never return null internal virtual void SetProperty(string name, object value) { MessageProperties prop = Properties; if (prop != null) { prop[name] = value; } } internal virtual bool GetProperty(string name, out object result) { MessageProperties prop = Properties; if (prop != null) { return prop.TryGetValue(name, out result); } result = null; return false; } internal virtual RecycledMessageState RecycledMessageState { get { return null; } } public MessageState State { get { return state; } } internal void BodyToString(XmlDictionaryWriter writer) { OnBodyToString(writer); } public void Close() { if (state != MessageState.Closed) { state = MessageState.Closed; OnClose(); if (DiagnosticUtility.ShouldTraceVerbose) { TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.MessageClosed, SR.GetString(SR.TraceCodeMessageClosed), this); } } else { if (DiagnosticUtility.ShouldTraceVerbose) { TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.MessageClosedAgain, SR.GetString(SR.TraceCodeMessageClosedAgain), this); } } } public MessageBuffer CreateBufferedCopy(int maxBufferSize) { if (maxBufferSize < 0) throw TraceUtility.ThrowHelperError(new ArgumentOutOfRangeException("maxBufferSize", maxBufferSize, SR.GetString(SR.ValueMustBeNonNegative)), this); switch (state) { case MessageState.Created: state = MessageState.Copied; if (DiagnosticUtility.ShouldTraceVerbose) { TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.MessageCopied, SR.GetString(SR.TraceCodeMessageCopied), this, this); } break; case MessageState.Closed: throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this); case MessageState.Copied: throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenCopied)), this); case MessageState.Read: throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenRead)), this); case MessageState.Written: throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenWritten)), this); default: Fx.Assert(SR.GetString(SR.InvalidMessageState)); throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidMessageState)), this); } return OnCreateBufferedCopy(maxBufferSize); } static Type GetObjectType(object value) { return (value == null) ? typeof(object) : value.GetType(); } static public Message CreateMessage(MessageVersion version, string action, object body) { return CreateMessage(version, action, body, DataContractSerializerDefaults.CreateSerializer(GetObjectType(body), int.MaxValue/*maxItems*/)); } static public Message CreateMessage(MessageVersion version, string action, object body, XmlObjectSerializer serializer) { if (version == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version")); if (serializer == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("serializer")); return new BodyWriterMessage(version, action, new XmlObjectSerializerBodyWriter(body, serializer)); } static public Message CreateMessage(MessageVersion version, string action, XmlReader body) { return CreateMessage(version, action, XmlDictionaryReader.CreateDictionaryReader(body)); } static public Message CreateMessage(MessageVersion version, string action, XmlDictionaryReader body) { if (body == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("body"); if (version == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("version"); return CreateMessage(version, action, new XmlReaderBodyWriter(body, version.Envelope)); } static public Message CreateMessage(MessageVersion version, string action, BodyWriter body) { if (version == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version")); if (body == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("body")); return new BodyWriterMessage(version, action, body); } static internal Message CreateMessage(MessageVersion version, ActionHeader actionHeader, BodyWriter body) { if (version == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version")); if (body == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("body")); return new BodyWriterMessage(version, actionHeader, body); } static public Message CreateMessage(MessageVersion version, string action) { if (version == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version")); return new BodyWriterMessage(version, action, EmptyBodyWriter.Value); } static internal Message CreateMessage(MessageVersion version, ActionHeader actionHeader) { if (version == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version")); return new BodyWriterMessage(version, actionHeader, EmptyBodyWriter.Value); } static public Message CreateMessage(XmlReader envelopeReader, int maxSizeOfHeaders, MessageVersion version) { return CreateMessage(XmlDictionaryReader.CreateDictionaryReader(envelopeReader), maxSizeOfHeaders, version); } static public Message CreateMessage(XmlDictionaryReader envelopeReader, int maxSizeOfHeaders, MessageVersion version) { if (envelopeReader == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("envelopeReader")); if (version == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version")); Message message = new StreamedMessage(envelopeReader, maxSizeOfHeaders, version); return message; } static public Message CreateMessage(MessageVersion version, FaultCode faultCode, string reason, string action) { if (version == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version")); if (faultCode == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("faultCode")); if (reason == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("reason")); return CreateMessage(version, MessageFault.CreateFault(faultCode, reason), action); } static public Message CreateMessage(MessageVersion version, FaultCode faultCode, string reason, object detail, string action) { if (version == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version")); if (faultCode == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("faultCode")); if (reason == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("reason")); return CreateMessage(version, MessageFault.CreateFault(faultCode, new FaultReason(reason), detail), action); } static public Message CreateMessage(MessageVersion version, MessageFault fault, string action) { if (fault == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("fault")); if (version == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version")); return new BodyWriterMessage(version, action, new FaultBodyWriter(fault, version.Envelope)); } internal Exception CreateMessageDisposedException() { return new ObjectDisposedException("", SR.GetString(SR.MessageClosed)); } void IDisposable.Dispose() { Close(); } public T GetBody() { XmlDictionaryReader reader = GetReaderAtBodyContents(); // This call will change the message state to Read. return OnGetBody(reader); } protected virtual T OnGetBody(XmlDictionaryReader reader) { return this.GetBodyCore(reader, DataContractSerializerDefaults.CreateSerializer(typeof(T), int.MaxValue/*maxItems*/)); } public T GetBody(XmlObjectSerializer serializer) { if (serializer == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("serializer")); return this.GetBodyCore(GetReaderAtBodyContents(), serializer); } T GetBodyCore(XmlDictionaryReader reader, XmlObjectSerializer serializer) { T value; using (reader) { value = (T)serializer.ReadObject(reader); this.ReadFromBodyContentsToEnd(reader); } return value; } internal virtual XmlDictionaryReader GetReaderAtHeader() { XmlBuffer buffer = new XmlBuffer(int.MaxValue); XmlDictionaryWriter writer = buffer.OpenSection(XmlDictionaryReaderQuotas.Max); WriteStartEnvelope(writer); MessageHeaders headers = this.Headers; for (int i = 0; i < headers.Count; i++) headers.WriteHeader(i, writer); writer.WriteEndElement(); writer.WriteEndElement(); buffer.CloseSection(); buffer.Close(); XmlDictionaryReader reader = buffer.GetReader(0); reader.ReadStartElement(); reader.MoveToStartElement(); return reader; } public XmlDictionaryReader GetReaderAtBodyContents() { EnsureReadMessageState(); if (IsEmpty) throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageIsEmpty)), this); return OnGetReaderAtBodyContents(); } internal void EnsureReadMessageState() { switch (state) { case MessageState.Created: state = MessageState.Read; if (DiagnosticUtility.ShouldTraceVerbose) { TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.MessageRead, SR.GetString(SR.TraceCodeMessageRead), this); } break; case MessageState.Copied: throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenCopied)), this); case MessageState.Read: throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenRead)), this); case MessageState.Written: throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenWritten)), this); case MessageState.Closed: throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this); default: Fx.Assert(SR.GetString(SR.InvalidMessageState)); throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidMessageState)), this); } } internal SeekableMessageNavigator GetNavigator(bool navigateBody, int maxNodes) { if (IsDisposed) throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this); if (null == this.messageNavigator) { this.messageNavigator = new SeekableMessageNavigator(this, maxNodes, XmlSpace.Default, navigateBody, false); } else { this.messageNavigator.ForkNodeCount(maxNodes); } return this.messageNavigator; } internal void InitializeReply(Message request) { UniqueId requestMessageID = request.Headers.MessageId; if (requestMessageID == null) throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.RequestMessageDoesNotHaveAMessageID)), request); Headers.RelatesTo = requestMessageID; } static internal bool IsFaultStartElement(XmlDictionaryReader reader, EnvelopeVersion version) { return reader.IsStartElement(XD.MessageDictionary.Fault, version.DictionaryNamespace); } protected virtual void OnBodyToString(XmlDictionaryWriter writer) { writer.WriteString(SR.GetString(SR.MessageBodyIsUnknown)); } protected virtual MessageBuffer OnCreateBufferedCopy(int maxBufferSize) { return OnCreateBufferedCopy(maxBufferSize, XmlDictionaryReaderQuotas.Max); } internal MessageBuffer OnCreateBufferedCopy(int maxBufferSize, XmlDictionaryReaderQuotas quotas) { XmlBuffer msgBuffer = new XmlBuffer(maxBufferSize); XmlDictionaryWriter writer = msgBuffer.OpenSection(quotas); OnWriteMessage(writer); msgBuffer.CloseSection(); msgBuffer.Close(); return new DefaultMessageBuffer(this, msgBuffer); } protected virtual void OnClose() { } protected virtual XmlDictionaryReader OnGetReaderAtBodyContents() { XmlBuffer bodyBuffer = new XmlBuffer(int.MaxValue); XmlDictionaryWriter writer = bodyBuffer.OpenSection(XmlDictionaryReaderQuotas.Max); if (this.Version.Envelope != EnvelopeVersion.None) { OnWriteStartEnvelope(writer); OnWriteStartBody(writer); } OnWriteBodyContents(writer); if (this.Version.Envelope != EnvelopeVersion.None) { writer.WriteEndElement(); writer.WriteEndElement(); } bodyBuffer.CloseSection(); bodyBuffer.Close(); XmlDictionaryReader reader = bodyBuffer.GetReader(0); if (this.Version.Envelope != EnvelopeVersion.None) { reader.ReadStartElement(); reader.ReadStartElement(); } reader.MoveToContent(); return reader; } protected virtual void OnWriteStartBody(XmlDictionaryWriter writer) { MessageDictionary messageDictionary = XD.MessageDictionary; writer.WriteStartElement(messageDictionary.Prefix.Value, messageDictionary.Body, Version.Envelope.DictionaryNamespace); } public void WriteBodyContents(XmlDictionaryWriter writer) { EnsureWriteMessageState(writer); OnWriteBodyContents(writer); } public IAsyncResult BeginWriteBodyContents(XmlDictionaryWriter writer, AsyncCallback callback, object state) { EnsureWriteMessageState(writer); return this.OnBeginWriteBodyContents(writer, callback, state); } public void EndWriteBodyContents(IAsyncResult result) { this.OnEndWriteBodyContents(result); } protected abstract void OnWriteBodyContents(XmlDictionaryWriter writer); protected virtual IAsyncResult OnBeginWriteBodyContents(XmlDictionaryWriter writer, AsyncCallback callback, object state) { return new OnWriteBodyContentsAsyncResult(writer, this, callback, state); } protected virtual void OnEndWriteBodyContents(IAsyncResult result) { OnWriteBodyContentsAsyncResult.End(result); } public void WriteStartEnvelope(XmlDictionaryWriter writer) { if (writer == null) throw TraceUtility.ThrowHelperError(new ArgumentNullException("writer"), this); OnWriteStartEnvelope(writer); } protected virtual void OnWriteStartEnvelope(XmlDictionaryWriter writer) { EnvelopeVersion envelopeVersion = Version.Envelope; if (envelopeVersion != EnvelopeVersion.None) { MessageDictionary messageDictionary = XD.MessageDictionary; writer.WriteStartElement(messageDictionary.Prefix.Value, messageDictionary.Envelope, envelopeVersion.DictionaryNamespace); WriteSharedHeaderPrefixes(writer); } } protected virtual void OnWriteStartHeaders(XmlDictionaryWriter writer) { EnvelopeVersion envelopeVersion = Version.Envelope; if (envelopeVersion != EnvelopeVersion.None) { MessageDictionary messageDictionary = XD.MessageDictionary; writer.WriteStartElement(messageDictionary.Prefix.Value, messageDictionary.Header, envelopeVersion.DictionaryNamespace); } } public override string ToString() { if (IsDisposed) { return base.ToString(); } StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); EncodingFallbackAwareXmlTextWriter textWriter = new EncodingFallbackAwareXmlTextWriter(stringWriter); textWriter.Formatting = Formatting.Indented; XmlDictionaryWriter writer = XmlDictionaryWriter.CreateDictionaryWriter(textWriter); try { ToString(writer); writer.Flush(); return stringWriter.ToString(); } catch (XmlException e) { return SR.GetString(SR.MessageBodyToStringError, e.GetType().ToString(), e.Message); } } internal void ToString(XmlDictionaryWriter writer) { if (IsDisposed) { throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this); } if (this.Version.Envelope != EnvelopeVersion.None) { WriteStartEnvelope(writer); WriteStartHeaders(writer); MessageHeaders headers = this.Headers; for (int i = 0; i < headers.Count; i++) { headers.WriteHeader(i, writer); } writer.WriteEndElement(); MessageDictionary messageDictionary = XD.MessageDictionary; WriteStartBody(writer); } BodyToString(writer); if (this.Version.Envelope != EnvelopeVersion.None) { writer.WriteEndElement(); writer.WriteEndElement(); } } public string GetBodyAttribute(string localName, string ns) { if (localName == null) throw TraceUtility.ThrowHelperError(new ArgumentNullException("localName"), this); if (ns == null) throw TraceUtility.ThrowHelperError(new ArgumentNullException("ns"), this); switch (state) { case MessageState.Created: break; case MessageState.Copied: throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenCopied)), this); case MessageState.Read: throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenRead)), this); case MessageState.Written: throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenWritten)), this); case MessageState.Closed: throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this); default: Fx.Assert(SR.GetString(SR.InvalidMessageState)); throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidMessageState)), this); } return OnGetBodyAttribute(localName, ns); } protected virtual string OnGetBodyAttribute(string localName, string ns) { return null; } internal void ReadFromBodyContentsToEnd(XmlDictionaryReader reader) { Message.ReadFromBodyContentsToEnd(reader, this.Version.Envelope); } static void ReadFromBodyContentsToEnd(XmlDictionaryReader reader, EnvelopeVersion envelopeVersion) { if (envelopeVersion != EnvelopeVersion.None) { reader.ReadEndElement(); // reader.ReadEndElement(); // } reader.MoveToContent(); } internal static bool ReadStartBody(XmlDictionaryReader reader, EnvelopeVersion envelopeVersion, out bool isFault, out bool isEmpty) { if (reader.IsEmptyElement) { reader.Read(); isEmpty = true; isFault = false; reader.ReadEndElement(); return false; } else { reader.Read(); if (reader.NodeType != XmlNodeType.Element) reader.MoveToContent(); if (reader.NodeType == XmlNodeType.Element) { isFault = IsFaultStartElement(reader, envelopeVersion); isEmpty = false; } else if (reader.NodeType == XmlNodeType.EndElement) { isEmpty = true; isFault = false; Message.ReadFromBodyContentsToEnd(reader, envelopeVersion); return false; } else { isEmpty = false; isFault = false; } return true; } } public void WriteBody(XmlWriter writer) { WriteBody(XmlDictionaryWriter.CreateDictionaryWriter(writer)); } public void WriteBody(XmlDictionaryWriter writer) { WriteStartBody(writer); WriteBodyContents(writer); writer.WriteEndElement(); } public void WriteStartBody(XmlWriter writer) { WriteStartBody(XmlDictionaryWriter.CreateDictionaryWriter(writer)); } public void WriteStartBody(XmlDictionaryWriter writer) { if (writer == null) throw TraceUtility.ThrowHelperError(new ArgumentNullException("writer"), this); OnWriteStartBody(writer); } internal void WriteStartHeaders(XmlDictionaryWriter writer) { OnWriteStartHeaders(writer); } public void WriteMessage(XmlWriter writer) { WriteMessage(XmlDictionaryWriter.CreateDictionaryWriter(writer)); } public void WriteMessage(XmlDictionaryWriter writer) { EnsureWriteMessageState(writer); OnWriteMessage(writer); } void EnsureWriteMessageState(XmlDictionaryWriter writer) { if (writer == null) throw TraceUtility.ThrowHelperError(new ArgumentNullException("writer"), this); switch (state) { case MessageState.Created: state = MessageState.Written; if (DiagnosticUtility.ShouldTraceVerbose) { TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.MessageWritten, SR.GetString(SR.TraceCodeMessageWritten), this); } break; case MessageState.Copied: throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenCopied)), this); case MessageState.Read: throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenRead)), this); case MessageState.Written: throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenWritten)), this); case MessageState.Closed: throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this); default: Fx.Assert(SR.GetString(SR.InvalidMessageState)); throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidMessageState)), this); } } public IAsyncResult BeginWriteMessage(XmlDictionaryWriter writer, AsyncCallback callback, object state) { EnsureWriteMessageState(writer); return OnBeginWriteMessage(writer, callback, state); } public void EndWriteMessage(IAsyncResult result) { OnEndWriteMessage(result); } protected virtual void OnWriteMessage(XmlDictionaryWriter writer) { WriteMessagePreamble(writer); OnWriteBodyContents(writer); WriteMessagePostamble(writer); } internal void WriteMessagePreamble(XmlDictionaryWriter writer) { if (this.Version.Envelope != EnvelopeVersion.None) { OnWriteStartEnvelope(writer); MessageHeaders headers = this.Headers; int headersCount = headers.Count; if (headersCount > 0) { OnWriteStartHeaders(writer); for (int i = 0; i < headersCount; i++) { headers.WriteHeader(i, writer); } writer.WriteEndElement(); } OnWriteStartBody(writer); } } internal void WriteMessagePostamble(XmlDictionaryWriter writer) { if (this.Version.Envelope != EnvelopeVersion.None) { writer.WriteEndElement(); writer.WriteEndElement(); } } protected virtual IAsyncResult OnBeginWriteMessage(XmlDictionaryWriter writer, AsyncCallback callback, object state) { return new OnWriteMessageAsyncResult(writer, this, callback, state); } protected virtual void OnEndWriteMessage(IAsyncResult result) { OnWriteMessageAsyncResult.End(result); } void WriteSharedHeaderPrefixes(XmlDictionaryWriter writer) { MessageHeaders headers = Headers; int count = headers.Count; int prefixesWritten = 0; for (int i = 0; i < count; i++) { if (this.Version.Addressing == AddressingVersion.None && headers[i].Namespace == AddressingVersion.None.Namespace) { continue; } IMessageHeaderWithSharedNamespace headerWithSharedNamespace = headers[i] as IMessageHeaderWithSharedNamespace; if (headerWithSharedNamespace != null) { XmlDictionaryString prefix = headerWithSharedNamespace.SharedPrefix; string prefixString = prefix.Value; if (!((prefixString.Length == 1))) { Fx.Assert("Message.WriteSharedHeaderPrefixes: (prefixString.Length == 1) -- IMessageHeaderWithSharedNamespace must use a single lowercase letter prefix."); throw TraceUtility.ThrowHelperError(new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "IMessageHeaderWithSharedNamespace must use a single lowercase letter prefix.")), this); } int prefixIndex = prefixString[0] - 'a'; if (!((prefixIndex >= 0 && prefixIndex < 26))) { Fx.Assert("Message.WriteSharedHeaderPrefixes: (prefixIndex >= 0 && prefixIndex < 26) -- IMessageHeaderWithSharedNamespace must use a single lowercase letter prefix."); throw TraceUtility.ThrowHelperError(new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "IMessageHeaderWithSharedNamespace must use a single lowercase letter prefix.")), this); } int prefixBit = 1 << prefixIndex; if ((prefixesWritten & prefixBit) == 0) { writer.WriteXmlnsAttribute(prefixString, headerWithSharedNamespace.SharedNamespace); prefixesWritten |= prefixBit; } } } } class OnWriteBodyContentsAsyncResult : ScheduleActionItemAsyncResult { Message message; XmlDictionaryWriter writer; public OnWriteBodyContentsAsyncResult(XmlDictionaryWriter writer, Message message, AsyncCallback callback, object state) : base(callback, state) { Fx.Assert(message != null, "message should never be null"); this.message = message; this.writer = writer; Schedule(); } protected override void OnDoWork() { this.message.OnWriteBodyContents(this.writer); } } class OnWriteMessageAsyncResult : ScheduleActionItemAsyncResult { Message message; XmlDictionaryWriter writer; public OnWriteMessageAsyncResult(XmlDictionaryWriter writer, Message message, AsyncCallback callback, object state) : base(callback, state) { Fx.Assert(message != null, "message should never be null"); this.message = message; this.writer = writer; Schedule(); } protected override void OnDoWork() { this.message.OnWriteMessage(this.writer); } } } class EmptyBodyWriter : BodyWriter { static EmptyBodyWriter value; EmptyBodyWriter() : base(true) { } public static EmptyBodyWriter Value { get { if (value == null) value = new EmptyBodyWriter(); return value; } } internal override bool IsEmpty { get { return true; } } protected override void OnWriteBodyContents(XmlDictionaryWriter writer) { } } class FaultBodyWriter : BodyWriter { MessageFault fault; EnvelopeVersion version; public FaultBodyWriter(MessageFault fault, EnvelopeVersion version) : base(true) { this.fault = fault; this.version = version; } internal override bool IsFault { get { return true; } } protected override void OnWriteBodyContents(XmlDictionaryWriter writer) { fault.WriteTo(writer, version); } } class XmlObjectSerializerBodyWriter : BodyWriter { object body; XmlObjectSerializer serializer; public XmlObjectSerializerBodyWriter(object body, XmlObjectSerializer serializer) : base(true) { this.body = body; this.serializer = serializer; } object ThisLock { get { return this; } } protected override void OnWriteBodyContents(XmlDictionaryWriter writer) { lock (ThisLock) { serializer.WriteObject(writer, body); } } } class XmlReaderBodyWriter : BodyWriter { XmlDictionaryReader reader; bool isFault; public XmlReaderBodyWriter(XmlDictionaryReader reader, EnvelopeVersion version) : base(false) { this.reader = reader; if (reader.MoveToContent() != XmlNodeType.Element) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.InvalidReaderPositionOnCreateMessage), "reader")); this.isFault = Message.IsFaultStartElement(reader, version); } internal override bool IsFault { get { return this.isFault; } } protected override BodyWriter OnCreateBufferedCopy(int maxBufferSize) { return OnCreateBufferedCopy(maxBufferSize, this.reader.Quotas); } protected override void OnWriteBodyContents(XmlDictionaryWriter writer) { using (reader) { XmlNodeType type = reader.MoveToContent(); while (!reader.EOF && type != XmlNodeType.EndElement) { if (type != XmlNodeType.Element) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.InvalidReaderPositionOnCreateMessage), "reader")); writer.WriteNode(reader, false); type = reader.MoveToContent(); } } } } class BodyWriterMessage : Message { MessageProperties properties; MessageHeaders headers; BodyWriter bodyWriter; BodyWriterMessage(BodyWriter bodyWriter) { this.bodyWriter = bodyWriter; } public BodyWriterMessage(MessageVersion version, string action, BodyWriter bodyWriter) : this(bodyWriter) { this.headers = new MessageHeaders(version); this.headers.Action = action; } public BodyWriterMessage(MessageVersion version, ActionHeader actionHeader, BodyWriter bodyWriter) : this(bodyWriter) { this.headers = new MessageHeaders(version); this.headers.SetActionHeader(actionHeader); } public BodyWriterMessage(MessageHeaders headers, KeyValuePair[] properties, BodyWriter bodyWriter) : this(bodyWriter) { this.headers = new MessageHeaders(headers); this.properties = new MessageProperties(properties); } public override bool IsFault { get { if (IsDisposed) #pragma warning suppress 56503 // Microsoft, Invalid State after dispose throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this); return bodyWriter.IsFault; } } public override bool IsEmpty { get { if (IsDisposed) #pragma warning suppress 56503 // Microsoft, Invalid State after dispose throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this); return bodyWriter.IsEmpty; } } public override MessageHeaders Headers { get { if (IsDisposed) #pragma warning suppress 56503 // Microsoft, Invalid State after dispose throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this); return headers; } } public override MessageProperties Properties { get { if (IsDisposed) #pragma warning suppress 56503 // Microsoft, Invalid State after dispose throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this); if (properties == null) properties = new MessageProperties(); return properties; } } internal override void SetProperty(string name, object value) { MessageProperties prop = this.properties; if (prop != null) { prop[name] = value; } } internal override bool GetProperty(string name, out object result) { MessageProperties prop = this.properties; if (prop != null) { return prop.TryGetValue(name, out result); } result = null; return false; } public override MessageVersion Version { get { if (IsDisposed) #pragma warning suppress 56503 // Microsoft, Invalid State after dispose throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this); return headers.MessageVersion; } } protected override MessageBuffer OnCreateBufferedCopy(int maxBufferSize) { BodyWriter bufferedBodyWriter; if (bodyWriter.IsBuffered) { bufferedBodyWriter = bodyWriter; } else { bufferedBodyWriter = bodyWriter.CreateBufferedCopy(maxBufferSize); } KeyValuePair[] properties = new KeyValuePair[Properties.Count]; ((ICollection>)Properties).CopyTo(properties, 0); return new BodyWriterMessageBuffer(headers, properties, bufferedBodyWriter); } protected override void OnClose() { Exception ex = null; try { base.OnClose(); } catch (Exception e) { if (Fx.IsFatal(e)) throw; ex = e; } try { if (properties != null) properties.Dispose(); } catch (Exception e) { if (Fx.IsFatal(e)) throw; if (ex == null) ex = e; } if (ex != null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(ex); bodyWriter = null; } protected override void OnWriteBodyContents(XmlDictionaryWriter writer) { bodyWriter.WriteBodyContents(writer); } protected override IAsyncResult OnBeginWriteMessage(XmlDictionaryWriter writer, AsyncCallback callback, object state) { WriteMessagePreamble(writer); return new OnWriteMessageAsyncResult(writer, this, callback, state); } protected override void OnEndWriteMessage(IAsyncResult result) { OnWriteMessageAsyncResult.End(result); } protected override IAsyncResult OnBeginWriteBodyContents(XmlDictionaryWriter writer, AsyncCallback callback, object state) { return bodyWriter.BeginWriteBodyContents(writer, callback, state); } protected override void OnEndWriteBodyContents(IAsyncResult result) { bodyWriter.EndWriteBodyContents(result); } protected override void OnBodyToString(XmlDictionaryWriter writer) { if (bodyWriter.IsBuffered) { bodyWriter.WriteBodyContents(writer); } else { writer.WriteString(SR.GetString(SR.MessageBodyIsStream)); } } protected internal BodyWriter BodyWriter { get { return bodyWriter; } } class OnWriteMessageAsyncResult : AsyncResult { BodyWriterMessage message; XmlDictionaryWriter writer; public OnWriteMessageAsyncResult(XmlDictionaryWriter writer, BodyWriterMessage message, AsyncCallback callback, object state) : base(callback, state) { this.message = message; this.writer = writer; if (HandleWriteBodyContents(null)) { this.Complete(true); } } bool HandleWriteBodyContents(IAsyncResult result) { if (result == null) { result = this.message.OnBeginWriteBodyContents(this.writer, PrepareAsyncCompletion(HandleWriteBodyContents), this); if (!result.CompletedSynchronously) { return false; } } this.message.OnEndWriteBodyContents(result); this.message.WriteMessagePostamble(this.writer); return true; } public static void End(IAsyncResult result) { AsyncResult.End(result); } } } abstract class ReceivedMessage : Message { bool isFault; bool isEmpty; public override bool IsEmpty { get { return isEmpty; } } public override bool IsFault { get { return isFault; } } protected static bool HasHeaderElement(XmlDictionaryReader reader, EnvelopeVersion envelopeVersion) { return reader.IsStartElement(XD.MessageDictionary.Header, envelopeVersion.DictionaryNamespace); } protected override void OnWriteBodyContents(XmlDictionaryWriter writer) { if (!isEmpty) { using (XmlDictionaryReader bodyReader = OnGetReaderAtBodyContents()) { if (bodyReader.ReadState == ReadState.Error || bodyReader.ReadState == ReadState.Closed) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageBodyReaderInvalidReadState, bodyReader.ReadState.ToString()))); while (bodyReader.NodeType != XmlNodeType.EndElement && !bodyReader.EOF) { writer.WriteNode(bodyReader, false); } this.ReadFromBodyContentsToEnd(bodyReader); } } } protected bool ReadStartBody(XmlDictionaryReader reader) { return Message.ReadStartBody(reader, this.Version.Envelope, out this.isFault, out this.isEmpty); } protected static EnvelopeVersion ReadStartEnvelope(XmlDictionaryReader reader) { EnvelopeVersion envelopeVersion; if (reader.IsStartElement(XD.MessageDictionary.Envelope, XD.Message12Dictionary.Namespace)) envelopeVersion = EnvelopeVersion.Soap12; else if (reader.IsStartElement(XD.MessageDictionary.Envelope, XD.Message11Dictionary.Namespace)) envelopeVersion = EnvelopeVersion.Soap11; else throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.MessageVersionUnknown))); if (reader.IsEmptyElement) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.MessageBodyMissing))); reader.Read(); return envelopeVersion; } protected static void VerifyStartBody(XmlDictionaryReader reader, EnvelopeVersion version) { if (!reader.IsStartElement(XD.MessageDictionary.Body, version.DictionaryNamespace)) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.MessageBodyMissing))); } } sealed class StreamedMessage : ReceivedMessage { MessageHeaders headers; XmlAttributeHolder[] envelopeAttributes; XmlAttributeHolder[] headerAttributes; XmlAttributeHolder[] bodyAttributes; string envelopePrefix; string headerPrefix; string bodyPrefix; MessageProperties properties; XmlDictionaryReader reader; XmlDictionaryReaderQuotas quotas; public StreamedMessage(XmlDictionaryReader reader, int maxSizeOfHeaders, MessageVersion desiredVersion) { properties = new MessageProperties(); if (reader.NodeType != XmlNodeType.Element) reader.MoveToContent(); if (desiredVersion.Envelope == EnvelopeVersion.None) { this.reader = reader; this.headerAttributes = XmlAttributeHolder.emptyArray; this.headers = new MessageHeaders(desiredVersion); } else { envelopeAttributes = XmlAttributeHolder.ReadAttributes(reader, ref maxSizeOfHeaders); envelopePrefix = reader.Prefix; EnvelopeVersion envelopeVersion = ReadStartEnvelope(reader); if (desiredVersion.Envelope != envelopeVersion) { Exception versionMismatchException = new ArgumentException(SR.GetString(SR.EncoderEnvelopeVersionMismatch, envelopeVersion, desiredVersion.Envelope), "reader"); throw TraceUtility.ThrowHelperError( new CommunicationException(versionMismatchException.Message, versionMismatchException), this); } if (HasHeaderElement(reader, envelopeVersion)) { headerPrefix = reader.Prefix; headerAttributes = XmlAttributeHolder.ReadAttributes(reader, ref maxSizeOfHeaders); headers = new MessageHeaders(desiredVersion, reader, envelopeAttributes, headerAttributes, ref maxSizeOfHeaders); } else { headerAttributes = XmlAttributeHolder.emptyArray; headers = new MessageHeaders(desiredVersion); } if (reader.NodeType != XmlNodeType.Element) reader.MoveToContent(); bodyPrefix = reader.Prefix; VerifyStartBody(reader, envelopeVersion); bodyAttributes = XmlAttributeHolder.ReadAttributes(reader, ref maxSizeOfHeaders); if (ReadStartBody(reader)) { this.reader = reader; } else { this.quotas = new XmlDictionaryReaderQuotas(); reader.Quotas.CopyTo(this.quotas); reader.Close(); } } } public override MessageHeaders Headers { get { if (IsDisposed) #pragma warning suppress 56503 // Microsoft, Invalid State after dispose throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this); return headers; } } public override MessageVersion Version { get { return headers.MessageVersion; } } public override MessageProperties Properties { get { return properties; } } protected override void OnBodyToString(XmlDictionaryWriter writer) { writer.WriteString(SR.GetString(SR.MessageBodyIsStream)); } protected override void OnClose() { Exception ex = null; try { base.OnClose(); } catch (Exception e) { if (Fx.IsFatal(e)) throw; ex = e; } try { properties.Dispose(); } catch (Exception e) { if (Fx.IsFatal(e)) throw; if (ex == null) ex = e; } try { if (reader != null) { reader.Close(); } } catch (Exception e) { if (Fx.IsFatal(e)) throw; if (ex == null) ex = e; } if (ex != null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(ex); } protected override XmlDictionaryReader OnGetReaderAtBodyContents() { XmlDictionaryReader reader = this.reader; this.reader = null; return reader; } protected override MessageBuffer OnCreateBufferedCopy(int maxBufferSize) { if (this.reader != null) return OnCreateBufferedCopy(maxBufferSize, this.reader.Quotas); return OnCreateBufferedCopy(maxBufferSize, this.quotas); } protected override void OnWriteStartBody(XmlDictionaryWriter writer) { writer.WriteStartElement(bodyPrefix, MessageStrings.Body, Version.Envelope.Namespace); XmlAttributeHolder.WriteAttributes(bodyAttributes, writer); } protected override void OnWriteStartEnvelope(XmlDictionaryWriter writer) { EnvelopeVersion envelopeVersion = Version.Envelope; writer.WriteStartElement(envelopePrefix, MessageStrings.Envelope, envelopeVersion.Namespace); XmlAttributeHolder.WriteAttributes(envelopeAttributes, writer); } protected override void OnWriteStartHeaders(XmlDictionaryWriter writer) { EnvelopeVersion envelopeVersion = Version.Envelope; writer.WriteStartElement(headerPrefix, MessageStrings.Header, envelopeVersion.Namespace); XmlAttributeHolder.WriteAttributes(headerAttributes, writer); } protected override string OnGetBodyAttribute(string localName, string ns) { return XmlAttributeHolder.GetAttribute(bodyAttributes, localName, ns); } } interface IBufferedMessageData { MessageEncoder MessageEncoder { get; } ArraySegment Buffer { get; } XmlDictionaryReaderQuotas Quotas { get; } void Close(); void EnableMultipleUsers(); XmlDictionaryReader GetMessageReader(); void Open(); void ReturnMessageState(RecycledMessageState messageState); RecycledMessageState TakeMessageState(); } sealed class BufferedMessage : ReceivedMessage { MessageHeaders headers; MessageProperties properties; IBufferedMessageData messageData; RecycledMessageState recycledMessageState; XmlDictionaryReader reader; XmlAttributeHolder[] bodyAttributes; public BufferedMessage(IBufferedMessageData messageData, RecycledMessageState recycledMessageState) : this(messageData, recycledMessageState, null, false) { } public BufferedMessage(IBufferedMessageData messageData, RecycledMessageState recycledMessageState, bool[] understoodHeaders, bool understoodHeadersModified) { bool throwing = true; try { this.recycledMessageState = recycledMessageState; this.messageData = messageData; properties = recycledMessageState.TakeProperties(); if (properties == null) this.properties = new MessageProperties(); XmlDictionaryReader reader = messageData.GetMessageReader(); MessageVersion desiredVersion = messageData.MessageEncoder.MessageVersion; if (desiredVersion.Envelope == EnvelopeVersion.None) { this.reader = reader; this.headers = new MessageHeaders(desiredVersion); } else { EnvelopeVersion envelopeVersion = ReadStartEnvelope(reader); if (desiredVersion.Envelope != envelopeVersion) { Exception versionMismatchException = new ArgumentException(SR.GetString(SR.EncoderEnvelopeVersionMismatch, envelopeVersion, desiredVersion.Envelope), "reader"); throw TraceUtility.ThrowHelperError( new CommunicationException(versionMismatchException.Message, versionMismatchException), this); } if (HasHeaderElement(reader, envelopeVersion)) { headers = recycledMessageState.TakeHeaders(); if (headers == null) { headers = new MessageHeaders(desiredVersion, reader, messageData, recycledMessageState, understoodHeaders, understoodHeadersModified); } else { headers.Init(desiredVersion, reader, messageData, recycledMessageState, understoodHeaders, understoodHeadersModified); } } else { headers = new MessageHeaders(desiredVersion); } VerifyStartBody(reader, envelopeVersion); int maxSizeOfAttributes = int.MaxValue; bodyAttributes = XmlAttributeHolder.ReadAttributes(reader, ref maxSizeOfAttributes); if (maxSizeOfAttributes < int.MaxValue - 4096) bodyAttributes = null; if (ReadStartBody(reader)) { this.reader = reader; } else { reader.Close(); } } throwing = false; } finally { if (throwing && MessageLogger.LoggingEnabled) { MessageLogger.LogMessage(messageData.Buffer, MessageLoggingSource.Malformed); } } } public override MessageHeaders Headers { get { if (IsDisposed) #pragma warning suppress 56503 // Microsoft, Invalid State after dispose throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this); return headers; } } internal IBufferedMessageData MessageData { get { return messageData; } } public override MessageProperties Properties { get { if (IsDisposed) #pragma warning suppress 56503 // Microsoft, Invalid State after dispose throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this); return properties; } } internal override RecycledMessageState RecycledMessageState { get { return recycledMessageState; } } public override MessageVersion Version { get { return headers.MessageVersion; } } protected override XmlDictionaryReader OnGetReaderAtBodyContents() { XmlDictionaryReader reader = this.reader; this.reader = null; return reader; } internal override XmlDictionaryReader GetReaderAtHeader() { if (!headers.ContainsOnlyBufferedMessageHeaders) return base.GetReaderAtHeader(); XmlDictionaryReader reader = messageData.GetMessageReader(); if (reader.NodeType != XmlNodeType.Element) reader.MoveToContent(); reader.Read(); if (HasHeaderElement(reader, headers.MessageVersion.Envelope)) return reader; return base.GetReaderAtHeader(); } public XmlDictionaryReader GetBufferedReaderAtBody() { XmlDictionaryReader reader = messageData.GetMessageReader(); if (reader.NodeType != XmlNodeType.Element) reader.MoveToContent(); if (this.Version.Envelope != EnvelopeVersion.None) { reader.Read(); if (HasHeaderElement(reader, headers.MessageVersion.Envelope)) reader.Skip(); if (reader.NodeType != XmlNodeType.Element) reader.MoveToContent(); } return reader; } public XmlDictionaryReader GetMessageReader() { return messageData.GetMessageReader(); } protected override void OnBodyToString(XmlDictionaryWriter writer) { using (XmlDictionaryReader reader = GetBufferedReaderAtBody()) { if (this.Version == MessageVersion.None) { writer.WriteNode(reader, false); } else { if (!reader.IsEmptyElement) { reader.ReadStartElement(); while (reader.NodeType != XmlNodeType.EndElement) writer.WriteNode(reader, false); } } } } protected override void OnClose() { Exception ex = null; try { base.OnClose(); } catch (Exception e) { if (Fx.IsFatal(e)) throw; ex = e; } try { properties.Dispose(); } catch (Exception e) { if (Fx.IsFatal(e)) throw; if (ex == null) ex = e; } try { if (reader != null) { reader.Close(); } } catch (Exception e) { if (Fx.IsFatal(e)) throw; if (ex == null) ex = e; } try { recycledMessageState.ReturnHeaders(headers); recycledMessageState.ReturnProperties(properties); messageData.ReturnMessageState(recycledMessageState); recycledMessageState = null; messageData.Close(); messageData = null; } catch (Exception e) { if (Fx.IsFatal(e)) throw; if (ex == null) ex = e; } if (ex != null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(ex); } protected override void OnWriteStartEnvelope(XmlDictionaryWriter writer) { using (XmlDictionaryReader reader = GetMessageReader()) { reader.MoveToContent(); EnvelopeVersion envelopeVersion = Version.Envelope; writer.WriteStartElement(reader.Prefix, MessageStrings.Envelope, envelopeVersion.Namespace); writer.WriteAttributes(reader, false); } } protected override void OnWriteStartHeaders(XmlDictionaryWriter writer) { using (XmlDictionaryReader reader = GetMessageReader()) { reader.MoveToContent(); EnvelopeVersion envelopeVersion = Version.Envelope; reader.Read(); if (HasHeaderElement(reader, envelopeVersion)) { writer.WriteStartElement(reader.Prefix, MessageStrings.Header, envelopeVersion.Namespace); writer.WriteAttributes(reader, false); } else { writer.WriteStartElement(MessageStrings.Prefix, MessageStrings.Header, envelopeVersion.Namespace); } } } protected override void OnWriteStartBody(XmlDictionaryWriter writer) { using (XmlDictionaryReader reader = GetBufferedReaderAtBody()) { writer.WriteStartElement(reader.Prefix, MessageStrings.Body, Version.Envelope.Namespace); writer.WriteAttributes(reader, false); } } protected override MessageBuffer OnCreateBufferedCopy(int maxBufferSize) { if (headers.ContainsOnlyBufferedMessageHeaders) { KeyValuePair[] properties = new KeyValuePair[Properties.Count]; ((ICollection>)Properties).CopyTo(properties, 0); messageData.EnableMultipleUsers(); bool[] understoodHeaders = null; if (headers.HasMustUnderstandBeenModified) { understoodHeaders = new bool[headers.Count]; for (int i = 0; i < headers.Count; i++) { understoodHeaders[i] = headers.IsUnderstood(i); } } return new BufferedMessageBuffer(messageData, properties, understoodHeaders, headers.HasMustUnderstandBeenModified); } else { if (this.reader != null) return OnCreateBufferedCopy(maxBufferSize, this.reader.Quotas); return OnCreateBufferedCopy(maxBufferSize, XmlDictionaryReaderQuotas.Max); } } protected override string OnGetBodyAttribute(string localName, string ns) { if (this.bodyAttributes != null) return XmlAttributeHolder.GetAttribute(this.bodyAttributes, localName, ns); using (XmlDictionaryReader reader = GetBufferedReaderAtBody()) { return reader.GetAttribute(localName, ns); } } } struct XmlAttributeHolder { string prefix; string ns; string localName; string value; public static XmlAttributeHolder[] emptyArray = new XmlAttributeHolder[0]; public XmlAttributeHolder(string prefix, string localName, string ns, string value) { this.prefix = prefix; this.localName = localName; this.ns = ns; this.value = value; } public string Prefix { get { return prefix; } } public string NamespaceUri { get { return ns; } } public string LocalName { get { return localName; } } public string Value { get { return value; } } public void WriteTo(XmlWriter writer) { writer.WriteStartAttribute(prefix, localName, ns); writer.WriteString(value); writer.WriteEndAttribute(); } public static void WriteAttributes(XmlAttributeHolder[] attributes, XmlWriter writer) { for (int i = 0; i < attributes.Length; i++) attributes[i].WriteTo(writer); } public static XmlAttributeHolder[] ReadAttributes(XmlDictionaryReader reader) { int maxSizeOfHeaders = int.MaxValue; return ReadAttributes(reader, ref maxSizeOfHeaders); } public static XmlAttributeHolder[] ReadAttributes(XmlDictionaryReader reader, ref int maxSizeOfHeaders) { if (reader.AttributeCount == 0) return emptyArray; XmlAttributeHolder[] attributes = new XmlAttributeHolder[reader.AttributeCount]; reader.MoveToFirstAttribute(); for (int i = 0; i < attributes.Length; i++) { string ns = reader.NamespaceURI; string localName = reader.LocalName; string prefix = reader.Prefix; string value = string.Empty; while (reader.ReadAttributeValue()) { if (value.Length == 0) value = reader.Value; else value += reader.Value; } Deduct(prefix, ref maxSizeOfHeaders); Deduct(localName, ref maxSizeOfHeaders); Deduct(ns, ref maxSizeOfHeaders); Deduct(value, ref maxSizeOfHeaders); attributes[i] = new XmlAttributeHolder(prefix, localName, ns, value); reader.MoveToNextAttribute(); } reader.MoveToElement(); return attributes; } static void Deduct(string s, ref int maxSizeOfHeaders) { int byteCount = s.Length * sizeof(char); if (byteCount > maxSizeOfHeaders) { string message = SR.GetString(SR.XmlBufferQuotaExceeded); Exception inner = new QuotaExceededException(message); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(message, inner)); } maxSizeOfHeaders -= byteCount; } public static string GetAttribute(XmlAttributeHolder[] attributes, string localName, string ns) { for (int i = 0; i < attributes.Length; i++) if (attributes[i].LocalName == localName && attributes[i].NamespaceUri == ns) return attributes[i].Value; return null; } } class RecycledMessageState { MessageHeaders recycledHeaders; MessageProperties recycledProperties; UriCache uriCache; HeaderInfoCache headerInfoCache; public HeaderInfoCache HeaderInfoCache { get { if (headerInfoCache == null) { headerInfoCache = new HeaderInfoCache(); } return headerInfoCache; } } public UriCache UriCache { get { if (uriCache == null) uriCache = new UriCache(); return uriCache; } } public MessageProperties TakeProperties() { MessageProperties taken = recycledProperties; recycledProperties = null; return taken; } public void ReturnProperties(MessageProperties properties) { if (properties.CanRecycle) { properties.Recycle(); this.recycledProperties = properties; } } public MessageHeaders TakeHeaders() { MessageHeaders taken = recycledHeaders; recycledHeaders = null; return taken; } public void ReturnHeaders(MessageHeaders headers) { if (headers.CanRecycle) { headers.Recycle(this.HeaderInfoCache); this.recycledHeaders = headers; } } } class HeaderInfoCache { const int maxHeaderInfos = 4; HeaderInfo[] headerInfos; int index; public MessageHeaderInfo TakeHeaderInfo(XmlDictionaryReader reader, string actor, bool mustUnderstand, bool relay, bool isRefParam) { if (this.headerInfos != null) { int i = this.index; for (;;) { HeaderInfo headerInfo = this.headerInfos[i]; if (headerInfo != null) { if (headerInfo.Matches(reader, actor, mustUnderstand, relay, isRefParam)) { this.headerInfos[i] = null; this.index = (i + 1) % maxHeaderInfos; return headerInfo; } } i = (i + 1) % maxHeaderInfos; if (i == this.index) { break; } } } return new HeaderInfo(reader, actor, mustUnderstand, relay, isRefParam); } public void ReturnHeaderInfo(MessageHeaderInfo headerInfo) { HeaderInfo headerInfoToReturn = headerInfo as HeaderInfo; if (headerInfoToReturn != null) { if (this.headerInfos == null) { this.headerInfos = new HeaderInfo[maxHeaderInfos]; } int i = this.index; for (;;) { if (this.headerInfos[i] == null) { break; } i = (i + 1) % maxHeaderInfos; if (i == this.index) { break; } } this.headerInfos[i] = headerInfoToReturn; this.index = (i + 1) % maxHeaderInfos; } } class HeaderInfo : MessageHeaderInfo { string name; string ns; string actor; bool isReferenceParameter; bool mustUnderstand; bool relay; public HeaderInfo(XmlDictionaryReader reader, string actor, bool mustUnderstand, bool relay, bool isReferenceParameter) { this.actor = actor; this.mustUnderstand = mustUnderstand; this.relay = relay; this.isReferenceParameter = isReferenceParameter; reader.GetNonAtomizedNames(out name, out ns); } public override string Name { get { return name; } } public override string Namespace { get { return ns; } } public override bool IsReferenceParameter { get { return isReferenceParameter; } } public override string Actor { get { return actor; } } public override bool MustUnderstand { get { return mustUnderstand; } } public override bool Relay { get { return relay; } } public bool Matches(XmlDictionaryReader reader, string actor, bool mustUnderstand, bool relay, bool isRefParam) { return reader.IsStartElement(this.name, this.ns) && this.actor == actor && this.mustUnderstand == mustUnderstand && this.relay == relay && this.isReferenceParameter == isRefParam; } } } class UriCache { const int MaxKeyLength = 128; const int MaxEntries = 8; Entry[] entries; int count; public UriCache() { entries = new Entry[MaxEntries]; } public Uri CreateUri(string uriString) { Uri uri = Get(uriString); if (uri == null) { uri = new Uri(uriString); Set(uriString, uri); } return uri; } Uri Get(string key) { if (key.Length > MaxKeyLength) return null; for (int i = count - 1; i >= 0; i--) if (entries[i].Key == key) return entries[i].Value; return null; } void Set(string key, Uri value) { if (key.Length > MaxKeyLength) return; if (count < entries.Length) { entries[count++] = new Entry(key, value); } else { Array.Copy(entries, 1, entries, 0, entries.Length - 1); entries[count - 1] = new Entry(key, value); } } struct Entry { string key; Uri value; public Entry(string key, Uri value) { this.key = key; this.value = value; } public string Key { get { return key; } } public Uri Value { get { return value; } } } } }