2
0

WebMessageFormatter.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. //
  2. // WebMessageFormatter.cs
  3. //
  4. // Author:
  5. // Atsushi Enomoto <[email protected]>
  6. // Atsushi Enomoto <[email protected]>
  7. //
  8. // Copyright (C) 2008,2009 Novell, Inc (http://www.novell.com)
  9. // Copyright (C) 2011 Xamarin, Inc (http://xamarin.com)
  10. //
  11. // Permission is hereby granted, free of charge, to any person obtaining
  12. // a copy of this software and associated documentation files (the
  13. // "Software"), to deal in the Software without restriction, including
  14. // without limitation the rights to use, copy, modify, merge, publish,
  15. // distribute, sublicense, and/or sell copies of the Software, and to
  16. // permit persons to whom the Software is furnished to do so, subject to
  17. // the following conditions:
  18. //
  19. // The above copyright notice and this permission notice shall be
  20. // included in all copies or substantial portions of the Software.
  21. //
  22. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  23. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  24. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  25. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  26. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  27. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  28. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  29. //
  30. using System;
  31. using System.Collections.Generic;
  32. using System.Globalization;
  33. using System.IO;
  34. using System.Reflection;
  35. using System.Runtime.Serialization;
  36. using System.Runtime.Serialization.Json;
  37. using System.ServiceModel;
  38. using System.ServiceModel.Channels;
  39. using System.ServiceModel.Description;
  40. using System.ServiceModel.Web;
  41. using System.Text;
  42. using System.Xml;
  43. #if NET_2_1
  44. using XmlObjectSerializer = System.Object;
  45. #endif
  46. namespace System.ServiceModel.Dispatcher
  47. {
  48. // This set of classes is to work as message formatters for
  49. // WebHttpBehavior. There are couple of aspects to differentiate
  50. // implementations:
  51. // - request/reply and client/server
  52. // by WebMessageFormatter hierarchy
  53. // - WebClientMessageFormatter - for client
  54. // - RequestClientFormatter - for request
  55. // - ReplyClientFormatter - for response
  56. // - WebDispatchMessageFormatter - for server
  57. // - RequestDispatchFormatter - for request
  58. // - ReplyDispatchFormatter - for response
  59. //
  60. // FIXME: below items need more work
  61. // - HTTP method differences
  62. // - GET (WebGet)
  63. // - POST (other way)
  64. // - output format: Stream, JSON, XML ...
  65. internal abstract class WebMessageFormatter
  66. {
  67. OperationDescription operation;
  68. ServiceEndpoint endpoint;
  69. QueryStringConverter converter;
  70. WebHttpBehavior behavior;
  71. UriTemplate template;
  72. WebAttributeInfo info = null;
  73. public WebMessageFormatter (OperationDescription operation, ServiceEndpoint endpoint, QueryStringConverter converter, WebHttpBehavior behavior)
  74. {
  75. this.operation = operation;
  76. this.endpoint = endpoint;
  77. this.converter = converter;
  78. this.behavior = behavior;
  79. ApplyWebAttribute ();
  80. #if !NET_2_1
  81. // This is a hack for WebScriptEnablingBehavior
  82. var jqc = converter as JsonQueryStringConverter;
  83. if (jqc != null)
  84. BodyName = jqc.CustomWrapperName;
  85. #endif
  86. }
  87. void ApplyWebAttribute ()
  88. {
  89. MethodInfo mi = operation.SyncMethod ?? operation.BeginMethod;
  90. object [] atts = mi.GetCustomAttributes (typeof (WebGetAttribute), false);
  91. if (atts.Length > 0)
  92. info = ((WebGetAttribute) atts [0]).Info;
  93. atts = mi.GetCustomAttributes (typeof (WebInvokeAttribute), false);
  94. if (atts.Length > 0)
  95. info = ((WebInvokeAttribute) atts [0]).Info;
  96. if (info == null)
  97. info = new WebAttributeInfo ();
  98. template = info.BuildUriTemplate (Operation, GetMessageDescription (MessageDirection.Input));
  99. }
  100. public string BodyName { get; set; }
  101. public WebHttpBehavior Behavior {
  102. get { return behavior; }
  103. }
  104. public WebAttributeInfo Info {
  105. get { return info; }
  106. }
  107. public WebMessageBodyStyle BodyStyle {
  108. get { return info.IsBodyStyleSetExplicitly ? info.BodyStyle : behavior.DefaultBodyStyle; }
  109. }
  110. public bool IsRequestBodyWrapped {
  111. get {
  112. switch (BodyStyle) {
  113. case WebMessageBodyStyle.Wrapped:
  114. case WebMessageBodyStyle.WrappedRequest:
  115. return true;
  116. }
  117. return BodyName != null;
  118. }
  119. }
  120. public bool IsResponseBodyWrapped {
  121. get {
  122. switch (BodyStyle) {
  123. case WebMessageBodyStyle.Wrapped:
  124. case WebMessageBodyStyle.WrappedResponse:
  125. return true;
  126. }
  127. return BodyName != null;
  128. }
  129. }
  130. public OperationDescription Operation {
  131. get { return operation; }
  132. }
  133. public QueryStringConverter Converter {
  134. get { return converter; }
  135. }
  136. public ServiceEndpoint Endpoint {
  137. get { return endpoint; }
  138. }
  139. public UriTemplate UriTemplate {
  140. get { return template; }
  141. }
  142. protected WebContentFormat ToContentFormat (WebMessageFormat src, object result)
  143. {
  144. if (result is Stream)
  145. return WebContentFormat.Raw;
  146. switch (src) {
  147. case WebMessageFormat.Xml:
  148. return WebContentFormat.Xml;
  149. case WebMessageFormat.Json:
  150. return WebContentFormat.Json;
  151. }
  152. throw new SystemException ("INTERNAL ERROR: should not happen");
  153. }
  154. protected string GetMediaTypeString (WebContentFormat fmt)
  155. {
  156. switch (fmt) {
  157. case WebContentFormat.Raw:
  158. return "application/octet-stream";
  159. case WebContentFormat.Json:
  160. return "application/json";
  161. case WebContentFormat.Xml:
  162. default:
  163. return "application/xml";
  164. }
  165. }
  166. protected void CheckMessageVersion (MessageVersion messageVersion)
  167. {
  168. if (messageVersion == null)
  169. throw new ArgumentNullException ("messageVersion");
  170. if (!MessageVersion.None.Equals (messageVersion))
  171. throw new ArgumentException (String.Format ("Only MessageVersion.None is supported. {0} is not.", messageVersion));
  172. }
  173. protected MessageDescription GetMessageDescription (MessageDirection dir)
  174. {
  175. foreach (MessageDescription md in operation.Messages)
  176. if (md.Direction == dir)
  177. return md;
  178. throw new SystemException ("INTERNAL ERROR: no corresponding message description for the specified direction: " + dir);
  179. }
  180. protected XmlObjectSerializer GetSerializer (WebContentFormat msgfmt, bool isWrapped, MessagePartDescription part)
  181. {
  182. if (part.Type == typeof (void))
  183. return null; // no serialization should be done.
  184. switch (msgfmt) {
  185. case WebContentFormat.Xml:
  186. if (xml_serializer == null)
  187. xml_serializer = isWrapped ? new DataContractSerializer (part.Type, part.Name, part.Namespace) : new DataContractSerializer (part.Type);
  188. return xml_serializer;
  189. case WebContentFormat.Json:
  190. // FIXME: after name argument they are hack
  191. if (json_serializer == null)
  192. json_serializer = isWrapped ? new DataContractJsonSerializer (part.Type, BodyName ?? part.Name, null, 0x100000, false, null, true) : new DataContractJsonSerializer (part.Type);
  193. return json_serializer;
  194. default:
  195. throw new NotImplementedException (msgfmt.ToString ());
  196. }
  197. }
  198. XmlObjectSerializer xml_serializer, json_serializer;
  199. protected object DeserializeObject (XmlObjectSerializer serializer, Message message, MessageDescription md, bool isWrapped, WebContentFormat fmt)
  200. {
  201. // FIXME: handle ref/out parameters
  202. var reader = message.GetReaderAtBodyContents ();
  203. reader.MoveToContent ();
  204. bool wasEmptyElement = reader.IsEmptyElement;
  205. if (isWrapped) {
  206. if (fmt == WebContentFormat.Json)
  207. reader.ReadStartElement ("root", String.Empty); // note that the wrapper name is passed to the serializer.
  208. else
  209. reader.ReadStartElement (md.Body.WrapperName, md.Body.WrapperNamespace);
  210. }
  211. var ret = (serializer == null) ? null : ReadObjectBody (serializer, reader);
  212. if (isWrapped && !wasEmptyElement)
  213. reader.ReadEndElement ();
  214. return ret;
  215. }
  216. protected object ReadObjectBody (XmlObjectSerializer serializer, XmlReader reader)
  217. {
  218. #if NET_2_1
  219. return (serializer is DataContractJsonSerializer) ?
  220. ((DataContractJsonSerializer) serializer).ReadObject (reader) :
  221. ((DataContractSerializer) serializer).ReadObject (reader, true);
  222. #else
  223. return serializer.ReadObject (reader, true);
  224. #endif
  225. }
  226. internal class RequestClientFormatter : WebClientMessageFormatter
  227. {
  228. public RequestClientFormatter (OperationDescription operation, ServiceEndpoint endpoint, QueryStringConverter converter, WebHttpBehavior behavior)
  229. : base (operation, endpoint, converter, behavior)
  230. {
  231. }
  232. public override object DeserializeReply (Message message, object [] parameters)
  233. {
  234. throw new NotSupportedException ();
  235. }
  236. }
  237. internal class ReplyClientFormatter : WebClientMessageFormatter
  238. {
  239. public ReplyClientFormatter (OperationDescription operation, ServiceEndpoint endpoint, QueryStringConverter converter, WebHttpBehavior behavior)
  240. : base (operation, endpoint, converter, behavior)
  241. {
  242. }
  243. public override Message SerializeRequest (MessageVersion messageVersion, object [] parameters)
  244. {
  245. throw new NotSupportedException ();
  246. }
  247. }
  248. #if !NET_2_1
  249. internal class RequestDispatchFormatter : WebDispatchMessageFormatter
  250. {
  251. public RequestDispatchFormatter (OperationDescription operation, ServiceEndpoint endpoint, QueryStringConverter converter, WebHttpBehavior behavior)
  252. : base (operation, endpoint, converter, behavior)
  253. {
  254. }
  255. public override Message SerializeReply (MessageVersion messageVersion, object [] parameters, object result)
  256. {
  257. throw new NotSupportedException ();
  258. }
  259. }
  260. internal class ReplyDispatchFormatter : WebDispatchMessageFormatter
  261. {
  262. public ReplyDispatchFormatter (OperationDescription operation, ServiceEndpoint endpoint, QueryStringConverter converter, WebHttpBehavior behavior)
  263. : base (operation, endpoint, converter, behavior)
  264. {
  265. }
  266. public override void DeserializeRequest (Message message, object [] parameters)
  267. {
  268. throw new NotSupportedException ();
  269. }
  270. }
  271. #endif
  272. internal abstract class WebClientMessageFormatter : WebMessageFormatter, IClientMessageFormatter
  273. {
  274. IClientMessageFormatter default_formatter;
  275. protected WebClientMessageFormatter (OperationDescription operation, ServiceEndpoint endpoint, QueryStringConverter converter, WebHttpBehavior behavior)
  276. : base (operation, endpoint, converter, behavior)
  277. {
  278. }
  279. public virtual Message SerializeRequest (MessageVersion messageVersion, object [] parameters)
  280. {
  281. if (parameters == null)
  282. throw new ArgumentNullException ("parameters");
  283. CheckMessageVersion (messageVersion);
  284. var c = new Dictionary<string,string> ();
  285. MessageDescription md = GetMessageDescription (MessageDirection.Input);
  286. Message ret;
  287. Uri to;
  288. object msgpart = null;
  289. for (int i = 0; i < parameters.Length; i++) {
  290. var p = md.Body.Parts [i];
  291. string name = p.Name.ToUpper (CultureInfo.InvariantCulture);
  292. if (UriTemplate.PathSegmentVariableNames.Contains (name) ||
  293. UriTemplate.QueryValueVariableNames.Contains (name))
  294. c.Add (name, parameters [i] != null ? Converter.ConvertValueToString (parameters [i], parameters [i].GetType ()) : null);
  295. else {
  296. // FIXME: bind as a message part
  297. if (msgpart == null)
  298. msgpart = parameters [i];
  299. else
  300. throw new NotImplementedException (String.Format ("More than one parameters including {0} that are not contained in the URI template {1} was found.", p.Name, UriTemplate));
  301. }
  302. }
  303. ret = Message.CreateMessage (messageVersion, (string) null, msgpart);
  304. to = UriTemplate.BindByName (Endpoint.Address.Uri, c);
  305. ret.Headers.To = to;
  306. var hp = new HttpRequestMessageProperty ();
  307. hp.Method = Info.Method;
  308. WebMessageFormat msgfmt = Info.IsResponseFormatSetExplicitly ? Info.ResponseFormat : Behavior.DefaultOutgoingResponseFormat;
  309. var contentFormat = ToContentFormat (msgfmt, msgpart);
  310. string mediaType = GetMediaTypeString (contentFormat);
  311. // FIXME: get encoding from somewhere
  312. hp.Headers ["Content-Type"] = mediaType + "; charset=utf-8";
  313. #if !NET_2_1
  314. if (WebOperationContext.Current != null)
  315. WebOperationContext.Current.OutgoingRequest.Apply (hp);
  316. #endif
  317. // FIXME: set hp.SuppressEntityBody for some cases.
  318. ret.Properties.Add (HttpRequestMessageProperty.Name, hp);
  319. var wp = new WebBodyFormatMessageProperty (ToContentFormat (Info.IsRequestFormatSetExplicitly ? Info.RequestFormat : Behavior.DefaultOutgoingRequestFormat, null));
  320. ret.Properties.Add (WebBodyFormatMessageProperty.Name, wp);
  321. return ret;
  322. }
  323. public virtual object DeserializeReply (Message message, object [] parameters)
  324. {
  325. if (parameters == null)
  326. throw new ArgumentNullException ("parameters");
  327. CheckMessageVersion (message.Version);
  328. #if !NET_2_1
  329. if (OperationContext.Current != null) {
  330. // Set response in the context
  331. OperationContext.Current.IncomingMessage = message;
  332. }
  333. #endif
  334. if (message.IsEmpty)
  335. return null; // empty message, could be returned by HttpReplyChannel.
  336. string pname = WebBodyFormatMessageProperty.Name;
  337. if (!message.Properties.ContainsKey (pname))
  338. throw new SystemException ("INTERNAL ERROR: it expects WebBodyFormatMessageProperty existence");
  339. var wp = (WebBodyFormatMessageProperty) message.Properties [pname];
  340. var fmt = wp != null ? wp.Format : WebContentFormat.Xml;
  341. var md = GetMessageDescription (MessageDirection.Output);
  342. var serializer = GetSerializer (wp.Format, IsResponseBodyWrapped, md.Body.ReturnValue);
  343. var ret = DeserializeObject (serializer, message, md, IsResponseBodyWrapped, fmt);
  344. return ret;
  345. }
  346. }
  347. internal class WrappedBodyWriter : BodyWriter
  348. {
  349. public WrappedBodyWriter (object value, XmlObjectSerializer serializer, string name, string ns, WebContentFormat fmt)
  350. : base (true)
  351. {
  352. this.name = name;
  353. this.ns = ns;
  354. this.value = value;
  355. this.serializer = serializer;
  356. this.fmt = fmt;
  357. }
  358. WebContentFormat fmt;
  359. string name, ns;
  360. object value;
  361. XmlObjectSerializer serializer;
  362. #if !NET_2_1
  363. protected override BodyWriter OnCreateBufferedCopy (int maxBufferSize)
  364. {
  365. return new WrappedBodyWriter (value, serializer, name, ns, fmt);
  366. }
  367. #endif
  368. protected override void OnWriteBodyContents (XmlDictionaryWriter writer)
  369. {
  370. switch (fmt) {
  371. case WebContentFormat.Raw:
  372. WriteRawContents (writer);
  373. break;
  374. case WebContentFormat.Json:
  375. WriteJsonBodyContents (writer);
  376. break;
  377. case WebContentFormat.Xml:
  378. WriteXmlBodyContents (writer);
  379. break;
  380. }
  381. }
  382. void WriteRawContents (XmlDictionaryWriter writer)
  383. {
  384. throw new NotSupportedException ("Some unsupported sequence of writing operation occured. It is likely a missing feature.");
  385. }
  386. void WriteJsonBodyContents (XmlDictionaryWriter writer)
  387. {
  388. if (name != null) {
  389. writer.WriteStartElement ("root");
  390. writer.WriteAttributeString ("type", "object");
  391. }
  392. WriteObject (serializer, writer, value);
  393. if (name != null)
  394. writer.WriteEndElement ();
  395. }
  396. void WriteXmlBodyContents (XmlDictionaryWriter writer)
  397. {
  398. if (name != null)
  399. writer.WriteStartElement (name, ns);
  400. WriteObject (serializer, writer, value);
  401. if (name != null)
  402. writer.WriteEndElement ();
  403. }
  404. void WriteObject (XmlObjectSerializer serializer, XmlDictionaryWriter writer, object value)
  405. {
  406. if (serializer != null){
  407. #if NET_2_1
  408. if (serializer is DataContractJsonSerializer)
  409. ((DataContractJsonSerializer) serializer).WriteObject (writer, value);
  410. else
  411. ((DataContractSerializer) serializer).WriteObject (writer, value);
  412. #else
  413. serializer.WriteObject (writer, value);
  414. #endif
  415. }
  416. }
  417. }
  418. #if !NET_2_1
  419. internal abstract class WebDispatchMessageFormatter : WebMessageFormatter, IDispatchMessageFormatter
  420. {
  421. protected WebDispatchMessageFormatter (OperationDescription operation, ServiceEndpoint endpoint, QueryStringConverter converter, WebHttpBehavior behavior)
  422. : base (operation, endpoint, converter, behavior)
  423. {
  424. }
  425. public virtual Message SerializeReply (MessageVersion messageVersion, object [] parameters, object result)
  426. {
  427. try {
  428. return SerializeReplyCore (messageVersion, parameters, result);
  429. } finally {
  430. if (WebOperationContext.Current != null)
  431. OperationContext.Current.Extensions.Remove (WebOperationContext.Current);
  432. }
  433. }
  434. Message SerializeReplyCore (MessageVersion messageVersion, object [] parameters, object result)
  435. {
  436. // parameters could be null.
  437. // result could be null. For Raw output, it becomes no output.
  438. CheckMessageVersion (messageVersion);
  439. MessageDescription md = GetMessageDescription (MessageDirection.Output);
  440. // FIXME: use them.
  441. // var dcob = Operation.Behaviors.Find<DataContractSerializerOperationBehavior> ();
  442. // XmlObjectSerializer xos = dcob.CreateSerializer (result.GetType (), md.Body.WrapperName, md.Body.WrapperNamespace, null);
  443. // var xsob = Operation.Behaviors.Find<XmlSerializerOperationBehavior> ();
  444. // XmlSerializer [] serializers = XmlSerializer.FromMappings (xsob.GetXmlMappings ().ToArray ());
  445. WebMessageFormat msgfmt = Info.IsResponseFormatSetExplicitly ? Info.ResponseFormat : Behavior.DefaultOutgoingResponseFormat;
  446. XmlObjectSerializer serializer = null;
  447. // FIXME: serialize ref/out parameters as well.
  448. string name = null, ns = null;
  449. switch (msgfmt) {
  450. case WebMessageFormat.Xml:
  451. serializer = GetSerializer (WebContentFormat.Xml, IsResponseBodyWrapped, md.Body.ReturnValue);
  452. name = IsResponseBodyWrapped ? md.Body.WrapperName : null;
  453. ns = IsResponseBodyWrapped ? md.Body.WrapperNamespace : null;
  454. break;
  455. case WebMessageFormat.Json:
  456. serializer = GetSerializer (WebContentFormat.Json, IsResponseBodyWrapped, md.Body.ReturnValue);
  457. name = IsResponseBodyWrapped ? (BodyName ?? md.Body.ReturnValue.Name) : null;
  458. ns = String.Empty;
  459. break;
  460. }
  461. var contentFormat = ToContentFormat (msgfmt, result);
  462. string mediaType = GetMediaTypeString (contentFormat);
  463. Message ret = contentFormat == WebContentFormat.Raw ? new RawMessage ((Stream) result) : Message.CreateMessage (MessageVersion.None, null, new WrappedBodyWriter (result, serializer, name, ns, contentFormat));
  464. // Message properties
  465. var hp = new HttpResponseMessageProperty ();
  466. // FIXME: get encoding from somewhere
  467. hp.Headers ["Content-Type"] = mediaType + "; charset=utf-8";
  468. // apply user-customized HTTP results via WebOperationContext.
  469. if (WebOperationContext.Current != null) // this formatter must be available outside ServiceHost.
  470. WebOperationContext.Current.OutgoingResponse.Apply (hp);
  471. // FIXME: fill some properties if required.
  472. ret.Properties.Add (HttpResponseMessageProperty.Name, hp);
  473. var wp = new WebBodyFormatMessageProperty (contentFormat);
  474. ret.Properties.Add (WebBodyFormatMessageProperty.Name, wp);
  475. return ret;
  476. }
  477. public virtual void DeserializeRequest (Message message, object [] parameters)
  478. {
  479. if (parameters == null)
  480. throw new ArgumentNullException ("parameters");
  481. CheckMessageVersion (message.Version);
  482. IncomingWebRequestContext iwc = null;
  483. if (OperationContext.Current != null) {
  484. OperationContext.Current.Extensions.Add (new WebOperationContext (OperationContext.Current));
  485. iwc = WebOperationContext.Current.IncomingRequest;
  486. }
  487. var wp = message.Properties [WebBodyFormatMessageProperty.Name] as WebBodyFormatMessageProperty;
  488. var fmt = wp != null ? wp.Format : WebContentFormat.Xml;
  489. Uri to = message.Headers.To;
  490. UriTemplateMatch match = to == null ? null : UriTemplate.Match (Endpoint.Address.Uri, to);
  491. if (match != null && iwc != null)
  492. iwc.UriTemplateMatch = match;
  493. MessageDescription md = GetMessageDescription (MessageDirection.Input);
  494. for (int i = 0; i < parameters.Length; i++) {
  495. var p = md.Body.Parts [i];
  496. string name = p.Name.ToUpperInvariant ();
  497. if (fmt == WebContentFormat.Raw && p.Type == typeof (Stream)) {
  498. var rmsg = (RawMessage) message;
  499. parameters [i] = rmsg.Stream;
  500. } else {
  501. var str = match.BoundVariables [name];
  502. if (str != null)
  503. parameters [i] = Converter.ConvertStringToValue (str, p.Type);
  504. else {
  505. if (info.Method != "GET") {
  506. var serializer = GetSerializer (fmt, IsRequestBodyWrapped, p);
  507. parameters [i] = DeserializeObject (serializer, message, md, IsRequestBodyWrapped, fmt);
  508. }
  509. // for GET Uri template parameters, there is no <anyType xsi:nil='true' />. So just skip the member.
  510. }
  511. }
  512. }
  513. }
  514. }
  515. #endif
  516. internal class RawMessage : Message
  517. {
  518. public RawMessage (Stream stream)
  519. {
  520. this.Stream = stream;
  521. headers = new MessageHeaders (MessageVersion.None);
  522. properties = new MessageProperties ();
  523. }
  524. public override MessageVersion Version {
  525. get { return MessageVersion.None; }
  526. }
  527. MessageHeaders headers;
  528. public override MessageHeaders Headers {
  529. get { return headers; }
  530. }
  531. MessageProperties properties;
  532. public override MessageProperties Properties {
  533. get { return properties; }
  534. }
  535. public Stream Stream { get; private set; }
  536. protected override void OnWriteBodyContents (XmlDictionaryWriter writer)
  537. {
  538. writer.WriteString ("-- message body is raw binary --");
  539. }
  540. protected override MessageBuffer OnCreateBufferedCopy (int maxBufferSize)
  541. {
  542. var ms = Stream as MemoryStream;
  543. if (ms == null) {
  544. ms = new MemoryStream ();
  545. Stream.CopyTo (ms);
  546. this.Stream = ms;
  547. }
  548. return new RawMessageBuffer (ms.ToArray (), headers, properties);
  549. }
  550. }
  551. internal class RawMessageBuffer : MessageBuffer
  552. {
  553. byte [] buffer;
  554. MessageHeaders headers;
  555. MessageProperties properties;
  556. public RawMessageBuffer (byte [] buffer, MessageHeaders headers, MessageProperties properties)
  557. {
  558. this.buffer = buffer;
  559. this.headers = new MessageHeaders (headers);
  560. this.properties = new MessageProperties (properties);
  561. }
  562. public override int BufferSize {
  563. get { return buffer.Length; }
  564. }
  565. public override void Close ()
  566. {
  567. }
  568. public override Message CreateMessage ()
  569. {
  570. var msg = new RawMessage (new MemoryStream (buffer));
  571. msg.Headers.CopyHeadersFrom (headers);
  572. msg.Properties.CopyProperties (properties);
  573. return msg;
  574. }
  575. }
  576. }
  577. }