Fix NET_2_1 builds.
[mono.git] / mcs / class / System.ServiceModel.Web / System.ServiceModel.Dispatcher / WebMessageFormatter.cs
1 //
2 // WebMessageFormatter.cs
3 //
4 // Author:
5 //      Atsushi Enomoto  <atsushi@ximian.com>
6 //      Atsushi Enomoto  <atsushi@xamarin.com>
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
44 #if NET_2_1
45 using XmlObjectSerializer = System.Object;
46 #endif
47
48 namespace System.ServiceModel.Dispatcher
49 {
50         // This set of classes is to work as message formatters for 
51         // WebHttpBehavior. There are couple of aspects to differentiate
52         // implementations:
53         // - request/reply and client/server
54         //   by WebMessageFormatter hierarchy
55         //   - WebClientMessageFormatter - for client
56         //     - RequestClientFormatter - for request
57         //     - ReplyClientFormatter - for response
58         //   - WebDispatchMessageFormatter - for server
59         //     - RequestDispatchFormatter - for request
60         //     - ReplyDispatchFormatter - for response
61         //
62         // FIXME: below items need more work
63         // - HTTP method differences
64         //  - GET (WebGet)
65         //  - POST (other way)
66         // - output format: Stream, JSON, XML ...
67
68         internal abstract class WebMessageFormatter
69         {
70                 OperationDescription operation;
71                 ServiceEndpoint endpoint;
72                 QueryStringConverter converter;
73                 WebHttpBehavior behavior;
74                 UriTemplate template;
75                 WebAttributeInfo info = null;
76
77                 public WebMessageFormatter (OperationDescription operation, ServiceEndpoint endpoint, QueryStringConverter converter, WebHttpBehavior behavior)
78                 {
79                         this.operation = operation;
80                         this.endpoint = endpoint;
81                         this.converter = converter;
82                         this.behavior = behavior;
83                         ApplyWebAttribute ();
84 #if !NET_2_1
85                         // This is a hack for WebScriptEnablingBehavior
86                         var jqc = converter as JsonQueryStringConverter;
87                         if (jqc != null)
88                                 BodyName = jqc.CustomWrapperName;
89 #endif
90                 }
91
92                 void ApplyWebAttribute ()
93                 {
94                         MethodInfo mi = operation.SyncMethod ?? operation.BeginMethod;
95
96                         object [] atts = mi.GetCustomAttributes (typeof (WebGetAttribute), false);
97                         if (atts.Length > 0)
98                                 info = ((WebGetAttribute) atts [0]).Info;
99                         atts = mi.GetCustomAttributes (typeof (WebInvokeAttribute), false);
100                         if (atts.Length > 0)
101                                 info = ((WebInvokeAttribute) atts [0]).Info;
102                         if (info == null)
103                                 info = new WebAttributeInfo ();
104
105                         template = info.BuildUriTemplate (Operation, GetMessageDescription (MessageDirection.Input));
106                 }
107
108                 public string BodyName { get; set; }
109
110                 public WebHttpBehavior Behavior {
111                         get { return behavior; }
112                 }
113
114                 public WebAttributeInfo Info {
115                         get { return info; }
116                 }
117
118                 public WebMessageBodyStyle BodyStyle {
119                         get { return info.IsBodyStyleSetExplicitly ? info.BodyStyle : behavior.DefaultBodyStyle; }
120                 }
121
122                 public bool IsRequestBodyWrapped {
123                         get {
124                                 switch (BodyStyle) {
125                                 case WebMessageBodyStyle.Wrapped:
126                                 case WebMessageBodyStyle.WrappedRequest:
127                                         return true;
128                                 }
129                                 return BodyName != null;
130                         }
131                 }
132
133                 public bool IsResponseBodyWrapped {
134                         get {
135                                 switch (BodyStyle) {
136                                 case WebMessageBodyStyle.Wrapped:
137                                 case WebMessageBodyStyle.WrappedResponse:
138                                         return true;
139                                 }
140                                 return BodyName != null;
141                         }
142                 }
143
144                 public OperationDescription Operation {
145                         get { return operation; }
146                 }
147
148                 public QueryStringConverter Converter {
149                         get { return converter; }
150                 }
151
152                 public ServiceEndpoint Endpoint {
153                         get { return endpoint; }
154                 }
155
156                 public UriTemplate UriTemplate {
157                         get { return template; }
158                 }
159
160                 protected WebContentFormat ToContentFormat (WebMessageFormat src, object result)
161                 {
162                         if (result is Stream)
163                                 return WebContentFormat.Raw;
164                         switch (src) {
165                         case WebMessageFormat.Xml:
166                                 return WebContentFormat.Xml;
167                         case WebMessageFormat.Json:
168                                 return WebContentFormat.Json;
169                         }
170                         throw new SystemException ("INTERNAL ERROR: should not happen");
171                 }
172
173                 protected string GetMediaTypeString (WebContentFormat fmt)
174                 {
175                         switch (fmt) {
176                         case WebContentFormat.Raw:
177                                 return "application/octet-stream";
178                         case WebContentFormat.Json:
179                                 return "application/json";
180                         case WebContentFormat.Xml:
181                         default:
182                                 return "application/xml";
183                         }
184                 }
185
186                 protected void CheckMessageVersion (MessageVersion messageVersion)
187                 {
188                         if (messageVersion == null)
189                                 throw new ArgumentNullException ("messageVersion");
190
191                         if (!MessageVersion.None.Equals (messageVersion))
192                                 throw new ArgumentException (String.Format ("Only MessageVersion.None is supported. {0} is not.", messageVersion));
193                 }
194
195                 protected MessageDescription GetMessageDescription (MessageDirection dir)
196                 {
197                         foreach (MessageDescription md in operation.Messages)
198                                 if (md.Direction == dir)
199                                         return md;
200                         throw new SystemException ("INTERNAL ERROR: no corresponding message description for the specified direction: " + dir);
201                 }
202
203                 protected XmlObjectSerializer GetSerializer (WebContentFormat msgfmt, bool isWrapped, MessagePartDescription part)
204                 {
205                         if (part.Type == typeof (void))
206                                 return null; // no serialization should be done.
207
208                         switch (msgfmt) {
209                         case WebContentFormat.Xml:
210                                 if (xml_serializer == null)
211                                         xml_serializer = isWrapped ? new DataContractSerializer (part.Type, part.Name, part.Namespace) : new DataContractSerializer (part.Type);
212                                 return xml_serializer;
213                         case WebContentFormat.Json:
214                                 // FIXME: after name argument they are hack
215                                 if (json_serializer == null)
216 #if MOONLIGHT
217                                         json_serializer = new DataContractJsonSerializer (part.Type);
218 #else
219                                         json_serializer = isWrapped ? new DataContractJsonSerializer (part.Type, BodyName ?? part.Name, null, 0x100000, false, null, true) : new DataContractJsonSerializer (part.Type);
220 #endif
221                                 return json_serializer;
222                         default:
223                                 throw new NotImplementedException (msgfmt.ToString ());
224                         }
225                 }
226
227                 XmlObjectSerializer xml_serializer, json_serializer;
228
229                 protected object DeserializeObject (XmlObjectSerializer serializer, Message message, MessageDescription md, bool isWrapped, WebContentFormat fmt)
230                 {
231                         // FIXME: handle ref/out parameters
232
233                         var reader = message.GetReaderAtBodyContents ();
234                         reader.MoveToContent ();
235
236                         bool wasEmptyElement = reader.IsEmptyElement;
237
238                         if (isWrapped) {
239                                 if (fmt == WebContentFormat.Json)
240                                         reader.ReadStartElement ("root", String.Empty); // note that the wrapper name is passed to the serializer.
241                                 else
242                                         reader.ReadStartElement (md.Body.WrapperName, md.Body.WrapperNamespace);
243                         }
244
245                         var ret = (serializer == null) ? null : ReadObjectBody (serializer, reader);
246
247                         if (isWrapped && !wasEmptyElement)
248                                 reader.ReadEndElement ();
249
250                         return ret;
251                 }
252                 
253                 protected object ReadObjectBody (XmlObjectSerializer serializer, XmlReader reader)
254                 {
255 #if NET_2_1
256                         return (serializer is DataContractJsonSerializer) ?
257                                 ((DataContractJsonSerializer) serializer).ReadObject (reader) :
258                                 ((DataContractSerializer) serializer).ReadObject (reader, true);
259 #else
260                         return serializer.ReadObject (reader, true);
261 #endif
262                 }
263
264                 internal class RequestClientFormatter : WebClientMessageFormatter
265                 {
266                         public RequestClientFormatter (OperationDescription operation, ServiceEndpoint endpoint, QueryStringConverter converter, WebHttpBehavior behavior)
267                                 : base (operation, endpoint, converter, behavior)
268                         {
269                         }
270
271                         public override object DeserializeReply (Message message, object [] parameters)
272                         {
273                                 throw new NotSupportedException ();
274                         }
275                 }
276
277                 internal class ReplyClientFormatter : WebClientMessageFormatter
278                 {
279                         public ReplyClientFormatter (OperationDescription operation, ServiceEndpoint endpoint, QueryStringConverter converter, WebHttpBehavior behavior)
280                                 : base (operation, endpoint, converter, behavior)
281                         {
282                         }
283
284                         public override Message SerializeRequest (MessageVersion messageVersion, object [] parameters)
285                         {
286                                 throw new NotSupportedException ();
287                         }
288                 }
289
290 #if !NET_2_1
291                 internal class RequestDispatchFormatter : WebDispatchMessageFormatter
292                 {
293                         public RequestDispatchFormatter (OperationDescription operation, ServiceEndpoint endpoint, QueryStringConverter converter, WebHttpBehavior behavior)
294                                 : base (operation, endpoint, converter, behavior)
295                         {
296                         }
297
298                         public override Message SerializeReply (MessageVersion messageVersion, object [] parameters, object result)
299                         {
300                                 throw new NotSupportedException ();
301                         }
302                 }
303
304                 internal class ReplyDispatchFormatter : WebDispatchMessageFormatter
305                 {
306                         public ReplyDispatchFormatter (OperationDescription operation, ServiceEndpoint endpoint, QueryStringConverter converter, WebHttpBehavior behavior)
307                                 : base (operation, endpoint, converter, behavior)
308                         {
309                         }
310
311                         public override void DeserializeRequest (Message message, object [] parameters)
312                         {
313                                 throw new NotSupportedException ();
314                         }
315                 }
316 #endif
317
318                 internal abstract class WebClientMessageFormatter : WebMessageFormatter, IClientMessageFormatter
319                 {
320                         IClientMessageFormatter default_formatter;
321
322                         protected WebClientMessageFormatter (OperationDescription operation, ServiceEndpoint endpoint, QueryStringConverter converter, WebHttpBehavior behavior)
323                                 : base (operation, endpoint, converter, behavior)
324                         {
325                         }
326
327                         public virtual Message SerializeRequest (MessageVersion messageVersion, object [] parameters)
328                         {
329                                 if (parameters == null)
330                                         throw new ArgumentNullException ("parameters");
331                                 CheckMessageVersion (messageVersion);
332
333                                 var c = new Dictionary<string,string> ();
334
335                                 MessageDescription md = GetMessageDescription (MessageDirection.Input);
336
337                                 Message ret;
338                                 Uri to;
339                                 object msgpart = null;
340
341
342                                 for (int i = 0; i < parameters.Length; i++) {
343                                         var p = md.Body.Parts [i];
344                                         string name = p.Name.ToUpper (CultureInfo.InvariantCulture);
345                                         if (UriTemplate.PathSegmentVariableNames.Contains (name) ||
346                                             UriTemplate.QueryValueVariableNames.Contains (name))
347                                                 c.Add (name, parameters [i] != null ? Converter.ConvertValueToString (parameters [i], parameters [i].GetType ()) : null);
348                                         else {
349                                                 // FIXME: bind as a message part
350                                                 if (msgpart == null)
351                                                         msgpart = parameters [i];
352                                                 else
353                                                         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));
354                                         }
355                                 }
356                                 ret = Message.CreateMessage (messageVersion, (string) null, msgpart);
357
358                                 to = UriTemplate.BindByName (Endpoint.Address.Uri, c);
359                                 ret.Headers.To = to;
360
361                                 var hp = new HttpRequestMessageProperty ();
362                                 hp.Method = Info.Method;
363
364                                 WebMessageFormat msgfmt = Info.IsResponseFormatSetExplicitly ? Info.ResponseFormat : Behavior.DefaultOutgoingResponseFormat;
365                                 var contentFormat = ToContentFormat (msgfmt, msgpart);
366                                 string mediaType = GetMediaTypeString (contentFormat);
367                                 // FIXME: get encoding from somewhere
368                                 hp.Headers ["Content-Type"] = mediaType + "; charset=utf-8";
369
370 #if !NET_2_1
371                                 if (WebOperationContext.Current != null)
372                                         WebOperationContext.Current.OutgoingRequest.Apply (hp);
373 #endif
374                                 // FIXME: set hp.SuppressEntityBody for some cases.
375                                 ret.Properties.Add (HttpRequestMessageProperty.Name, hp);
376
377                                 var wp = new WebBodyFormatMessageProperty (ToContentFormat (Info.IsRequestFormatSetExplicitly ? Info.RequestFormat : Behavior.DefaultOutgoingRequestFormat, null));
378                                 ret.Properties.Add (WebBodyFormatMessageProperty.Name, wp);
379
380                                 return ret;
381                         }
382
383                         public virtual object DeserializeReply (Message message, object [] parameters)
384                         {
385                                 if (parameters == null)
386                                         throw new ArgumentNullException ("parameters");
387                                 CheckMessageVersion (message.Version);
388
389 #if !NET_2_1
390                                 if (OperationContext.Current != null) {
391                                         // Set response in the context
392                                         OperationContext.Current.IncomingMessage = message;
393                                 }
394 #endif
395
396                                 if (message.IsEmpty)
397                                         return null; // empty message, could be returned by HttpReplyChannel.
398
399                                 string pname = WebBodyFormatMessageProperty.Name;
400                                 if (!message.Properties.ContainsKey (pname))
401                                         throw new SystemException ("INTERNAL ERROR: it expects WebBodyFormatMessageProperty existence");
402                                 var wp = (WebBodyFormatMessageProperty) message.Properties [pname];
403                                 var fmt = wp != null ? wp.Format : WebContentFormat.Xml;
404
405                                 var md = GetMessageDescription (MessageDirection.Output);
406                                 var serializer = GetSerializer (wp.Format, IsResponseBodyWrapped, md.Body.ReturnValue);
407                                 var ret = DeserializeObject (serializer, message, md, IsResponseBodyWrapped, fmt);
408
409                                 return ret;
410                         }
411                 }
412
413                 internal class WrappedBodyWriter : BodyWriter
414                 {
415                         public WrappedBodyWriter (object value, XmlObjectSerializer serializer, string name, string ns, WebContentFormat fmt)
416                                 : base (true)
417                         {
418                                 this.name = name;
419                                 this.ns = ns;
420                                 this.value = value;
421                                 this.serializer = serializer;
422                                 this.fmt = fmt;
423                         }
424
425                         WebContentFormat fmt;
426                         string name, ns;
427                         object value;
428                         XmlObjectSerializer serializer;
429
430 #if !NET_2_1
431                         protected override BodyWriter OnCreateBufferedCopy (int maxBufferSize)
432                         {
433                                 return new WrappedBodyWriter (value, serializer, name, ns, fmt);
434                         }
435 #endif
436
437                         protected override void OnWriteBodyContents (XmlDictionaryWriter writer)
438                         {
439                                 switch (fmt) {
440                                 case WebContentFormat.Raw:
441                                         WriteRawContents (writer);
442                                         break;
443                                 case WebContentFormat.Json:
444                                         WriteJsonBodyContents (writer);
445                                         break;
446                                 case WebContentFormat.Xml:
447                                         WriteXmlBodyContents (writer);
448                                         break;
449                                 }
450                         }
451                         
452                         void WriteRawContents (XmlDictionaryWriter writer)
453                         {
454                                 throw new NotSupportedException ("Some unsupported sequence of writing operation occured. It is likely a missing feature.");
455                         }
456                         
457                         void WriteJsonBodyContents (XmlDictionaryWriter writer)
458                         {
459                                 if (name != null) {
460                                         writer.WriteStartElement ("root");
461                                         writer.WriteAttributeString ("type", "object");
462                                 }
463                                 WriteObject (serializer, writer, value);
464                                 if (name != null)
465                                         writer.WriteEndElement ();
466                         }
467
468                         void WriteXmlBodyContents (XmlDictionaryWriter writer)
469                         {
470                                 if (name != null)
471                                         writer.WriteStartElement (name, ns);
472                                 WriteObject (serializer, writer, value);
473                                 if (name != null)
474                                         writer.WriteEndElement ();
475                         }
476
477                         void WriteObject (XmlObjectSerializer serializer, XmlDictionaryWriter writer, object value)
478                         {
479 #if NET_2_1
480                                         if (serializer is DataContractJsonSerializer)
481                                                 ((DataContractJsonSerializer) serializer).WriteObject (writer, value);
482                                         else
483                                                 ((DataContractSerializer) serializer).WriteObject (writer, value);
484 #else
485                                         serializer.WriteObject (writer, value);
486 #endif
487                         }
488                 }
489
490 #if !NET_2_1
491                 internal abstract class WebDispatchMessageFormatter : WebMessageFormatter, IDispatchMessageFormatter
492                 {
493                         protected WebDispatchMessageFormatter (OperationDescription operation, ServiceEndpoint endpoint, QueryStringConverter converter, WebHttpBehavior behavior)
494                                 : base (operation, endpoint, converter, behavior)
495                         {
496                         }
497
498                         public virtual Message SerializeReply (MessageVersion messageVersion, object [] parameters, object result)
499                         {
500                                 try {
501                                         return SerializeReplyCore (messageVersion, parameters, result);
502                                 } finally {
503                                         if (WebOperationContext.Current != null)
504                                                 OperationContext.Current.Extensions.Remove (WebOperationContext.Current);
505                                 }
506                         }
507
508                         Message SerializeReplyCore (MessageVersion messageVersion, object [] parameters, object result)
509                         {
510                                 // parameters could be null.
511                                 // result could be null. For Raw output, it becomes no output.
512
513                                 CheckMessageVersion (messageVersion);
514
515                                 MessageDescription md = GetMessageDescription (MessageDirection.Output);
516
517                                 // FIXME: use them.
518                                 // var dcob = Operation.Behaviors.Find<DataContractSerializerOperationBehavior> ();
519                                 // XmlObjectSerializer xos = dcob.CreateSerializer (result.GetType (), md.Body.WrapperName, md.Body.WrapperNamespace, null);
520                                 // var xsob = Operation.Behaviors.Find<XmlSerializerOperationBehavior> ();
521                                 // XmlSerializer [] serializers = XmlSerializer.FromMappings (xsob.GetXmlMappings ().ToArray ());
522
523                                 WebMessageFormat msgfmt = Info.IsResponseFormatSetExplicitly ? Info.ResponseFormat : Behavior.DefaultOutgoingResponseFormat;
524
525                                 XmlObjectSerializer serializer = null;
526
527                                 // FIXME: serialize ref/out parameters as well.
528
529                                 string name = null, ns = null;
530
531                                 switch (msgfmt) {
532                                 case WebMessageFormat.Xml:
533                                         serializer = GetSerializer (WebContentFormat.Xml, IsResponseBodyWrapped, md.Body.ReturnValue);
534                                         name = IsResponseBodyWrapped ? md.Body.WrapperName : null;
535                                         ns = IsResponseBodyWrapped ? md.Body.WrapperNamespace : null;
536                                         break;
537                                 case WebMessageFormat.Json:
538                                         serializer = GetSerializer (WebContentFormat.Json, IsResponseBodyWrapped, md.Body.ReturnValue);
539                                         name = IsResponseBodyWrapped ? (BodyName ?? md.Body.ReturnValue.Name) : null;
540                                         ns = String.Empty;
541                                         break;
542                                 }
543
544                                 var contentFormat = ToContentFormat (msgfmt, result);
545                                 string mediaType = GetMediaTypeString (contentFormat);
546                                 Message ret = contentFormat == WebContentFormat.Raw ? new RawMessage ((Stream) result) : Message.CreateMessage (MessageVersion.None, null, new WrappedBodyWriter (result, serializer, name, ns, contentFormat));
547
548                                 // Message properties
549
550                                 var hp = new HttpResponseMessageProperty ();
551                                 // FIXME: get encoding from somewhere
552                                 hp.Headers ["Content-Type"] = mediaType + "; charset=utf-8";
553
554                                 // apply user-customized HTTP results via WebOperationContext.
555                                 if (WebOperationContext.Current != null) // this formatter must be available outside ServiceHost.
556                                         WebOperationContext.Current.OutgoingResponse.Apply (hp);
557
558                                 // FIXME: fill some properties if required.
559                                 ret.Properties.Add (HttpResponseMessageProperty.Name, hp);
560
561                                 var wp = new WebBodyFormatMessageProperty (contentFormat);
562                                 ret.Properties.Add (WebBodyFormatMessageProperty.Name, wp);
563
564                                 return ret;
565                         }
566
567                         public virtual void DeserializeRequest (Message message, object [] parameters)
568                         {
569                                 if (parameters == null)
570                                         throw new ArgumentNullException ("parameters");
571                                 CheckMessageVersion (message.Version);
572
573                                 IncomingWebRequestContext iwc = null;
574                                 if (OperationContext.Current != null) {
575                                         OperationContext.Current.Extensions.Add (new WebOperationContext (OperationContext.Current));
576                                         iwc = WebOperationContext.Current.IncomingRequest;
577                                 }
578                                 
579                                 var wp = message.Properties [WebBodyFormatMessageProperty.Name] as WebBodyFormatMessageProperty;
580                                 var fmt = wp != null ? wp.Format : WebContentFormat.Xml;
581
582                                 Uri to = message.Headers.To;
583                                 UriTemplateMatch match = to == null ? null : UriTemplate.Match (Endpoint.Address.Uri, to);
584                                 if (match != null && iwc != null)
585                                         iwc.UriTemplateMatch = match;
586
587                                 MessageDescription md = GetMessageDescription (MessageDirection.Input);
588
589                                 for (int i = 0; i < parameters.Length; i++) {
590                                         var p = md.Body.Parts [i];
591                                         string name = p.Name.ToUpperInvariant ();
592                                         if (fmt == WebContentFormat.Raw && p.Type == typeof (Stream)) {
593                                                 var rmsg = (RawMessage) message;
594                                                 parameters [i] = rmsg.Stream;
595                                         } else {
596                                                 var str = match.BoundVariables [name];
597                                                 if (str != null)
598                                                         parameters [i] = Converter.ConvertStringToValue (str, p.Type);
599                                                 else {
600                                                         if (info.Method != "GET") {
601                                                                 var serializer = GetSerializer (fmt, IsRequestBodyWrapped, p);
602                                                                 parameters [i] = DeserializeObject (serializer, message, md, IsRequestBodyWrapped, fmt);
603                                                         }
604                                                         // for GET Uri template parameters, there is no <anyType xsi:nil='true' />. So just skip the member.
605                                                 }
606                                         }
607                                 }
608                         }
609                 }
610 #endif
611
612                 internal class RawMessage : Message
613                 {
614                         public RawMessage (Stream stream)
615                         {
616                                 this.Stream = stream;
617                                 headers = new MessageHeaders (MessageVersion.None);
618                                 properties = new MessageProperties ();
619                         }
620                 
621                         public override MessageVersion Version {
622                                 get { return MessageVersion.None; }
623                         }
624                 
625                         MessageHeaders headers;
626
627                         public override MessageHeaders Headers {
628                                 get { return headers; }
629                         }
630                 
631                         MessageProperties properties;
632
633                         public override MessageProperties Properties {
634                                 get { return properties; }
635                         }
636
637                         public Stream Stream { get; private set; }
638
639                         protected override void OnWriteBodyContents (XmlDictionaryWriter writer)
640                         {
641                                 writer.WriteString ("-- message body is raw binary --");
642                         }
643
644                         protected override MessageBuffer OnCreateBufferedCopy (int maxBufferSize)
645                         {
646                                 var ms = Stream as MemoryStream;
647                                 if (ms == null) {
648                                         ms = new MemoryStream ();
649 #if NET_4_0 || NET_2_1
650                                         Stream.CopyTo (ms);
651 #else
652                                         byte [] tmp = new byte [0x1000];
653                                         int size;
654                                         do {
655                                                 size = Stream.Read (tmp, 0, tmp.Length);
656                                                 ms.Write (tmp, 0, size);
657                                         } while (size > 0);
658 #endif
659                                         this.Stream = ms;
660                                 }
661                                 return new RawMessageBuffer (ms.ToArray (), headers, properties);
662                         }
663                 }
664                 
665                 internal class RawMessageBuffer : MessageBuffer
666                 {
667                         byte [] buffer;
668                         MessageHeaders headers;
669                         MessageProperties properties;
670
671                         public RawMessageBuffer (byte [] buffer, MessageHeaders headers, MessageProperties properties)
672                         {
673                                 this.buffer = buffer;
674                                 this.headers = new MessageHeaders (headers);
675                                 this.properties = new MessageProperties (properties);
676                         }
677                         
678                         public override int BufferSize {
679                                 get { return buffer.Length; }
680                         }
681                         
682                         public override void Close ()
683                         {
684                         }
685                         
686                         public override Message CreateMessage ()
687                         {
688                                 var msg = new RawMessage (new MemoryStream (buffer));
689                                 msg.Headers.CopyHeadersFrom (headers);
690                                 msg.Properties.CopyProperties (properties);
691                                 return msg;
692                         }
693                 }
694         }
695 }