StreamFormatter.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel.Dispatcher
  5. {
  6. using System.IO;
  7. using System.Runtime;
  8. using System.ServiceModel;
  9. using System.ServiceModel.Channels;
  10. using System.ServiceModel.Description;
  11. using System.ServiceModel.Diagnostics;
  12. using System.Xml;
  13. class StreamFormatter
  14. {
  15. string wrapperName;
  16. string wrapperNS;
  17. string partName;
  18. string partNS;
  19. int streamIndex;
  20. bool isRequest;
  21. string operationName;
  22. const int returnValueIndex = -1;
  23. internal static StreamFormatter Create(MessageDescription messageDescription, string operationName, bool isRequest)
  24. {
  25. MessagePartDescription streamPart = ValidateAndGetStreamPart(messageDescription, isRequest, operationName);
  26. if (streamPart == null)
  27. return null;
  28. return new StreamFormatter(messageDescription, streamPart, operationName, isRequest);
  29. }
  30. StreamFormatter(MessageDescription messageDescription, MessagePartDescription streamPart, string operationName, bool isRequest)
  31. {
  32. if ((object)streamPart == (object)messageDescription.Body.ReturnValue)
  33. this.streamIndex = returnValueIndex;
  34. else
  35. this.streamIndex = streamPart.Index;
  36. wrapperName = messageDescription.Body.WrapperName;
  37. wrapperNS = messageDescription.Body.WrapperNamespace;
  38. partName = streamPart.Name;
  39. partNS = streamPart.Namespace;
  40. this.isRequest = isRequest;
  41. this.operationName = operationName;
  42. }
  43. internal void Serialize(XmlDictionaryWriter writer, object[] parameters, object returnValue)
  44. {
  45. Stream streamValue = GetStreamAndWriteStartWrapperIfNecessary(writer, parameters, returnValue);
  46. writer.WriteValue(new OperationStreamProvider(streamValue));
  47. WriteEndWrapperIfNecessary(writer);
  48. }
  49. Stream GetStreamAndWriteStartWrapperIfNecessary(XmlDictionaryWriter writer, object[] parameters, object returnValue)
  50. {
  51. Stream streamValue = GetStreamValue(parameters, returnValue);
  52. if (streamValue == null)
  53. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(partName);
  54. if (WrapperName != null)
  55. writer.WriteStartElement(WrapperName, WrapperNamespace);
  56. writer.WriteStartElement(PartName, PartNamespace);
  57. return streamValue;
  58. }
  59. void WriteEndWrapperIfNecessary(XmlDictionaryWriter writer)
  60. {
  61. writer.WriteEndElement();
  62. if (wrapperName != null)
  63. writer.WriteEndElement();
  64. }
  65. internal IAsyncResult BeginSerialize(XmlDictionaryWriter writer, object[] parameters, object returnValue, AsyncCallback callback, object state)
  66. {
  67. return new SerializeAsyncResult(this, writer, parameters, returnValue, callback, state);
  68. }
  69. public void EndSerialize(IAsyncResult result)
  70. {
  71. SerializeAsyncResult.End(result);
  72. }
  73. class SerializeAsyncResult : AsyncResult
  74. {
  75. static AsyncCompletion handleEndSerialize = new AsyncCompletion(HandleEndSerialize);
  76. StreamFormatter streamFormatter;
  77. XmlDictionaryWriter writer;
  78. internal SerializeAsyncResult(StreamFormatter streamFormatter, XmlDictionaryWriter writer, object[] parameters, object returnValue,
  79. AsyncCallback callback, object state)
  80. : base(callback, state)
  81. {
  82. this.streamFormatter = streamFormatter;
  83. this.writer = writer;
  84. bool completeSelf = true;
  85. Stream streamValue = streamFormatter.GetStreamAndWriteStartWrapperIfNecessary(writer, parameters, returnValue);
  86. IAsyncResult result = writer.WriteValueAsync(new OperationStreamProvider(streamValue)).AsAsyncResult(PrepareAsyncCompletion(handleEndSerialize), this);
  87. completeSelf = SyncContinue(result);
  88. // Note: The current task implementation hard codes the "IAsyncResult.CompletedSynchronously" property to false, so this fast path will never
  89. // be hit, and we will always hop threads. CSDMain #210220
  90. if (completeSelf)
  91. {
  92. Complete(true);
  93. }
  94. }
  95. static bool HandleEndSerialize(IAsyncResult result)
  96. {
  97. SerializeAsyncResult thisPtr = (SerializeAsyncResult)result.AsyncState;
  98. thisPtr.streamFormatter.WriteEndWrapperIfNecessary(thisPtr.writer);
  99. return true;
  100. }
  101. public static void End(IAsyncResult result)
  102. {
  103. AsyncResult.End<SerializeAsyncResult>(result);
  104. }
  105. }
  106. internal void Deserialize(object[] parameters, ref object retVal, Message message)
  107. {
  108. SetStreamValue(parameters, ref retVal, new MessageBodyStream(message, WrapperName, WrapperNamespace, PartName, PartNamespace, isRequest));
  109. }
  110. internal string WrapperName
  111. {
  112. get { return wrapperName; }
  113. set { wrapperName = value; }
  114. }
  115. internal string WrapperNamespace
  116. {
  117. get { return wrapperNS; }
  118. set { wrapperNS = value; }
  119. }
  120. internal string PartName
  121. {
  122. get { return partName; }
  123. }
  124. internal string PartNamespace
  125. {
  126. get { return partNS; }
  127. }
  128. Stream GetStreamValue(object[] parameters, object returnValue)
  129. {
  130. if (streamIndex == returnValueIndex)
  131. return (Stream)returnValue;
  132. return (Stream)parameters[streamIndex];
  133. }
  134. void SetStreamValue(object[] parameters, ref object returnValue, Stream streamValue)
  135. {
  136. if (streamIndex == returnValueIndex)
  137. returnValue = streamValue;
  138. else
  139. parameters[streamIndex] = streamValue;
  140. }
  141. static MessagePartDescription ValidateAndGetStreamPart(MessageDescription messageDescription, bool isRequest, string operationName)
  142. {
  143. MessagePartDescription part = GetStreamPart(messageDescription);
  144. if (part != null)
  145. return part;
  146. if (HasStream(messageDescription))
  147. {
  148. if (messageDescription.IsTypedMessage)
  149. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidStreamInTypedMessage, messageDescription.MessageName)));
  150. else if (isRequest)
  151. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidStreamInRequest, operationName)));
  152. else
  153. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidStreamInResponse, operationName)));
  154. }
  155. return null;
  156. }
  157. private static bool HasStream(MessageDescription messageDescription)
  158. {
  159. if (messageDescription.Body.ReturnValue != null && messageDescription.Body.ReturnValue.Type == typeof(Stream))
  160. return true;
  161. foreach (MessagePartDescription part in messageDescription.Body.Parts)
  162. {
  163. if (part.Type == typeof(Stream))
  164. return true;
  165. }
  166. return false;
  167. }
  168. static MessagePartDescription GetStreamPart(MessageDescription messageDescription)
  169. {
  170. if (OperationFormatter.IsValidReturnValue(messageDescription.Body.ReturnValue))
  171. {
  172. if (messageDescription.Body.Parts.Count == 0)
  173. if (messageDescription.Body.ReturnValue.Type == typeof(Stream))
  174. return messageDescription.Body.ReturnValue;
  175. }
  176. else
  177. {
  178. if (messageDescription.Body.Parts.Count == 1)
  179. if (messageDescription.Body.Parts[0].Type == typeof(Stream))
  180. return messageDescription.Body.Parts[0];
  181. }
  182. return null;
  183. }
  184. internal static bool IsStream(MessageDescription messageDescription)
  185. {
  186. return GetStreamPart(messageDescription) != null;
  187. }
  188. internal class MessageBodyStream : Stream
  189. {
  190. Message message;
  191. XmlDictionaryReader reader;
  192. long position;
  193. string wrapperName, wrapperNs;
  194. string elementName, elementNs;
  195. bool isRequest;
  196. internal MessageBodyStream(Message message, string wrapperName, string wrapperNs, string elementName, string elementNs, bool isRequest)
  197. {
  198. this.message = message;
  199. this.position = 0;
  200. this.wrapperName = wrapperName;
  201. this.wrapperNs = wrapperNs;
  202. this.elementName = elementName;
  203. this.elementNs = elementNs;
  204. this.isRequest = isRequest;
  205. }
  206. public override int Read(byte[] buffer, int offset, int count)
  207. {
  208. EnsureStreamIsOpen();
  209. if (buffer == null)
  210. throw TraceUtility.ThrowHelperError(new ArgumentNullException("buffer"), this.message);
  211. if (offset < 0)
  212. throw TraceUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", offset,
  213. SR.GetString(SR.ValueMustBeNonNegative)), this.message);
  214. if (count < 0)
  215. throw TraceUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", count,
  216. SR.GetString(SR.ValueMustBeNonNegative)), this.message);
  217. if (buffer.Length - offset < count)
  218. throw TraceUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.SFxInvalidStreamOffsetLength, offset + count)), this.message);
  219. try
  220. {
  221. if (reader == null)
  222. {
  223. reader = message.GetReaderAtBodyContents();
  224. if (wrapperName != null)
  225. {
  226. reader.MoveToContent();
  227. reader.ReadStartElement(wrapperName, wrapperNs);
  228. }
  229. reader.MoveToContent();
  230. if (reader.NodeType == XmlNodeType.EndElement)
  231. {
  232. return 0;
  233. }
  234. reader.ReadStartElement(elementName, elementNs);
  235. }
  236. if (reader.MoveToContent() != XmlNodeType.Text)
  237. {
  238. Exhaust(reader);
  239. return 0;
  240. }
  241. int bytesRead = reader.ReadContentAsBase64(buffer, offset, count);
  242. position += bytesRead;
  243. if (bytesRead == 0)
  244. {
  245. Exhaust(reader);
  246. }
  247. return bytesRead;
  248. }
  249. catch (Exception ex)
  250. {
  251. if (Fx.IsFatal(ex))
  252. throw;
  253. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new IOException(SR.GetString(SR.SFxStreamIOException), ex));
  254. }
  255. }
  256. private void EnsureStreamIsOpen()
  257. {
  258. if (message.State == MessageState.Closed)
  259. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ObjectDisposedException(SR.GetString(
  260. isRequest ? SR.SFxStreamRequestMessageClosed : SR.SFxStreamResponseMessageClosed)));
  261. }
  262. static void Exhaust(XmlDictionaryReader reader)
  263. {
  264. if (reader != null)
  265. {
  266. while (reader.Read())
  267. {
  268. // drain
  269. }
  270. }
  271. }
  272. public override long Position
  273. {
  274. get
  275. {
  276. EnsureStreamIsOpen();
  277. return position;
  278. }
  279. set { throw TraceUtility.ThrowHelperError(new NotSupportedException(), message); }
  280. }
  281. public override void Close()
  282. {
  283. message.Close();
  284. if (reader != null)
  285. {
  286. reader.Close();
  287. reader = null;
  288. }
  289. base.Close();
  290. }
  291. public override bool CanRead { get { return message.State != MessageState.Closed; } }
  292. public override bool CanSeek { get { return false; } }
  293. public override bool CanWrite { get { return false; } }
  294. public override long Length
  295. {
  296. get
  297. {
  298. #pragma warning suppress 56503 // [....], not a seekable stream, it is ok to throw NotSupported in this case
  299. throw TraceUtility.ThrowHelperError(new NotSupportedException(), this.message);
  300. }
  301. }
  302. public override void Flush() { throw TraceUtility.ThrowHelperError(new NotSupportedException(), this.message); }
  303. public override long Seek(long offset, SeekOrigin origin) { throw TraceUtility.ThrowHelperError(new NotSupportedException(), this.message); }
  304. public override void SetLength(long value) { throw TraceUtility.ThrowHelperError(new NotSupportedException(), this.message); }
  305. public override void Write(byte[] buffer, int offset, int count) { throw TraceUtility.ThrowHelperError(new NotSupportedException(), this.message); }
  306. }
  307. class OperationStreamProvider : IStreamProvider
  308. {
  309. Stream stream;
  310. internal OperationStreamProvider(Stream stream)
  311. {
  312. this.stream = stream;
  313. }
  314. public Stream GetStream()
  315. {
  316. return stream;
  317. }
  318. public void ReleaseStream(Stream stream)
  319. {
  320. //Noop
  321. }
  322. }
  323. }
  324. }