| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- //-----------------------------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //-----------------------------------------------------------------------------
- namespace System.ServiceModel.Dispatcher
- {
- using System.IO;
- using System.Runtime;
- using System.ServiceModel;
- using System.ServiceModel.Channels;
- using System.ServiceModel.Description;
- using System.ServiceModel.Diagnostics;
- using System.Xml;
- class StreamFormatter
- {
- string wrapperName;
- string wrapperNS;
- string partName;
- string partNS;
- int streamIndex;
- bool isRequest;
- string operationName;
- const int returnValueIndex = -1;
- internal static StreamFormatter Create(MessageDescription messageDescription, string operationName, bool isRequest)
- {
- MessagePartDescription streamPart = ValidateAndGetStreamPart(messageDescription, isRequest, operationName);
- if (streamPart == null)
- return null;
- return new StreamFormatter(messageDescription, streamPart, operationName, isRequest);
- }
- StreamFormatter(MessageDescription messageDescription, MessagePartDescription streamPart, string operationName, bool isRequest)
- {
- if ((object)streamPart == (object)messageDescription.Body.ReturnValue)
- this.streamIndex = returnValueIndex;
- else
- this.streamIndex = streamPart.Index;
- wrapperName = messageDescription.Body.WrapperName;
- wrapperNS = messageDescription.Body.WrapperNamespace;
- partName = streamPart.Name;
- partNS = streamPart.Namespace;
- this.isRequest = isRequest;
- this.operationName = operationName;
- }
- internal void Serialize(XmlDictionaryWriter writer, object[] parameters, object returnValue)
- {
- Stream streamValue = GetStreamAndWriteStartWrapperIfNecessary(writer, parameters, returnValue);
- writer.WriteValue(new OperationStreamProvider(streamValue));
- WriteEndWrapperIfNecessary(writer);
- }
- Stream GetStreamAndWriteStartWrapperIfNecessary(XmlDictionaryWriter writer, object[] parameters, object returnValue)
- {
- Stream streamValue = GetStreamValue(parameters, returnValue);
- if (streamValue == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(partName);
- if (WrapperName != null)
- writer.WriteStartElement(WrapperName, WrapperNamespace);
- writer.WriteStartElement(PartName, PartNamespace);
- return streamValue;
- }
- void WriteEndWrapperIfNecessary(XmlDictionaryWriter writer)
- {
- writer.WriteEndElement();
- if (wrapperName != null)
- writer.WriteEndElement();
- }
- internal IAsyncResult BeginSerialize(XmlDictionaryWriter writer, object[] parameters, object returnValue, AsyncCallback callback, object state)
- {
- return new SerializeAsyncResult(this, writer, parameters, returnValue, callback, state);
- }
- public void EndSerialize(IAsyncResult result)
- {
- SerializeAsyncResult.End(result);
- }
- class SerializeAsyncResult : AsyncResult
- {
- static AsyncCompletion handleEndSerialize = new AsyncCompletion(HandleEndSerialize);
- StreamFormatter streamFormatter;
- XmlDictionaryWriter writer;
- internal SerializeAsyncResult(StreamFormatter streamFormatter, XmlDictionaryWriter writer, object[] parameters, object returnValue,
- AsyncCallback callback, object state)
- : base(callback, state)
- {
- this.streamFormatter = streamFormatter;
- this.writer = writer;
- bool completeSelf = true;
- Stream streamValue = streamFormatter.GetStreamAndWriteStartWrapperIfNecessary(writer, parameters, returnValue);
- IAsyncResult result = writer.WriteValueAsync(new OperationStreamProvider(streamValue)).AsAsyncResult(PrepareAsyncCompletion(handleEndSerialize), this);
- completeSelf = SyncContinue(result);
- // Note: The current task implementation hard codes the "IAsyncResult.CompletedSynchronously" property to false, so this fast path will never
- // be hit, and we will always hop threads. CSDMain #210220
- if (completeSelf)
- {
- Complete(true);
- }
- }
- static bool HandleEndSerialize(IAsyncResult result)
- {
- SerializeAsyncResult thisPtr = (SerializeAsyncResult)result.AsyncState;
- thisPtr.streamFormatter.WriteEndWrapperIfNecessary(thisPtr.writer);
- return true;
- }
- public static void End(IAsyncResult result)
- {
- AsyncResult.End<SerializeAsyncResult>(result);
- }
- }
- internal void Deserialize(object[] parameters, ref object retVal, Message message)
- {
- SetStreamValue(parameters, ref retVal, new MessageBodyStream(message, WrapperName, WrapperNamespace, PartName, PartNamespace, isRequest));
- }
- internal string WrapperName
- {
- get { return wrapperName; }
- set { wrapperName = value; }
- }
- internal string WrapperNamespace
- {
- get { return wrapperNS; }
- set { wrapperNS = value; }
- }
- internal string PartName
- {
- get { return partName; }
- }
- internal string PartNamespace
- {
- get { return partNS; }
- }
- Stream GetStreamValue(object[] parameters, object returnValue)
- {
- if (streamIndex == returnValueIndex)
- return (Stream)returnValue;
- return (Stream)parameters[streamIndex];
- }
- void SetStreamValue(object[] parameters, ref object returnValue, Stream streamValue)
- {
- if (streamIndex == returnValueIndex)
- returnValue = streamValue;
- else
- parameters[streamIndex] = streamValue;
- }
- static MessagePartDescription ValidateAndGetStreamPart(MessageDescription messageDescription, bool isRequest, string operationName)
- {
- MessagePartDescription part = GetStreamPart(messageDescription);
- if (part != null)
- return part;
- if (HasStream(messageDescription))
- {
- if (messageDescription.IsTypedMessage)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidStreamInTypedMessage, messageDescription.MessageName)));
- else if (isRequest)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidStreamInRequest, operationName)));
- else
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidStreamInResponse, operationName)));
- }
- return null;
- }
- private static bool HasStream(MessageDescription messageDescription)
- {
- if (messageDescription.Body.ReturnValue != null && messageDescription.Body.ReturnValue.Type == typeof(Stream))
- return true;
- foreach (MessagePartDescription part in messageDescription.Body.Parts)
- {
- if (part.Type == typeof(Stream))
- return true;
- }
- return false;
- }
- static MessagePartDescription GetStreamPart(MessageDescription messageDescription)
- {
- if (OperationFormatter.IsValidReturnValue(messageDescription.Body.ReturnValue))
- {
- if (messageDescription.Body.Parts.Count == 0)
- if (messageDescription.Body.ReturnValue.Type == typeof(Stream))
- return messageDescription.Body.ReturnValue;
- }
- else
- {
- if (messageDescription.Body.Parts.Count == 1)
- if (messageDescription.Body.Parts[0].Type == typeof(Stream))
- return messageDescription.Body.Parts[0];
- }
- return null;
- }
- internal static bool IsStream(MessageDescription messageDescription)
- {
- return GetStreamPart(messageDescription) != null;
- }
- internal class MessageBodyStream : Stream
- {
- Message message;
- XmlDictionaryReader reader;
- long position;
- string wrapperName, wrapperNs;
- string elementName, elementNs;
- bool isRequest;
- internal MessageBodyStream(Message message, string wrapperName, string wrapperNs, string elementName, string elementNs, bool isRequest)
- {
- this.message = message;
- this.position = 0;
- this.wrapperName = wrapperName;
- this.wrapperNs = wrapperNs;
- this.elementName = elementName;
- this.elementNs = elementNs;
- this.isRequest = isRequest;
- }
- public override int Read(byte[] buffer, int offset, int count)
- {
- EnsureStreamIsOpen();
- if (buffer == null)
- throw TraceUtility.ThrowHelperError(new ArgumentNullException("buffer"), this.message);
- if (offset < 0)
- throw TraceUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", offset,
- SR.GetString(SR.ValueMustBeNonNegative)), this.message);
- if (count < 0)
- throw TraceUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", count,
- SR.GetString(SR.ValueMustBeNonNegative)), this.message);
- if (buffer.Length - offset < count)
- throw TraceUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.SFxInvalidStreamOffsetLength, offset + count)), this.message);
- try
- {
- if (reader == null)
- {
- reader = message.GetReaderAtBodyContents();
- if (wrapperName != null)
- {
- reader.MoveToContent();
- reader.ReadStartElement(wrapperName, wrapperNs);
- }
- reader.MoveToContent();
- if (reader.NodeType == XmlNodeType.EndElement)
- {
- return 0;
- }
- reader.ReadStartElement(elementName, elementNs);
- }
- if (reader.MoveToContent() != XmlNodeType.Text)
- {
- Exhaust(reader);
- return 0;
- }
- int bytesRead = reader.ReadContentAsBase64(buffer, offset, count);
- position += bytesRead;
- if (bytesRead == 0)
- {
- Exhaust(reader);
- }
- return bytesRead;
- }
- catch (Exception ex)
- {
- if (Fx.IsFatal(ex))
- throw;
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new IOException(SR.GetString(SR.SFxStreamIOException), ex));
- }
- }
- private void EnsureStreamIsOpen()
- {
- if (message.State == MessageState.Closed)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ObjectDisposedException(SR.GetString(
- isRequest ? SR.SFxStreamRequestMessageClosed : SR.SFxStreamResponseMessageClosed)));
- }
- static void Exhaust(XmlDictionaryReader reader)
- {
- if (reader != null)
- {
- while (reader.Read())
- {
- // drain
- }
- }
- }
- public override long Position
- {
- get
- {
- EnsureStreamIsOpen();
- return position;
- }
- set { throw TraceUtility.ThrowHelperError(new NotSupportedException(), message); }
- }
- public override void Close()
- {
- message.Close();
- if (reader != null)
- {
- reader.Close();
- reader = null;
- }
- base.Close();
- }
- public override bool CanRead { get { return message.State != MessageState.Closed; } }
- public override bool CanSeek { get { return false; } }
- public override bool CanWrite { get { return false; } }
- public override long Length
- {
- get
- {
- #pragma warning suppress 56503 // [....], not a seekable stream, it is ok to throw NotSupported in this case
- throw TraceUtility.ThrowHelperError(new NotSupportedException(), this.message);
- }
- }
- public override void Flush() { throw TraceUtility.ThrowHelperError(new NotSupportedException(), this.message); }
- public override long Seek(long offset, SeekOrigin origin) { throw TraceUtility.ThrowHelperError(new NotSupportedException(), this.message); }
- public override void SetLength(long value) { throw TraceUtility.ThrowHelperError(new NotSupportedException(), this.message); }
- public override void Write(byte[] buffer, int offset, int count) { throw TraceUtility.ThrowHelperError(new NotSupportedException(), this.message); }
- }
- class OperationStreamProvider : IStreamProvider
- {
- Stream stream;
- internal OperationStreamProvider(Stream stream)
- {
- this.stream = stream;
- }
- public Stream GetStream()
- {
- return stream;
- }
- public void ReleaseStream(Stream stream)
- {
- //Noop
- }
- }
- }
- }
|