2010-07-14 Atsushi Enomoto <atsushi@ximian.com>
authorAtsushi Eno <atsushieno@gmail.com>
Wed, 14 Jul 2010 08:43:31 +0000 (08:43 -0000)
committerAtsushi Eno <atsushieno@gmail.com>
Wed, 14 Jul 2010 08:43:31 +0000 (08:43 -0000)
* WebMessageFormatter.cs : add support for Raw format.

* WebMessageEncoder.cs : support Raw message. Fixed bug #619542.

* WebHttpBehaviorTest.cs : add test for bug #619542 (not sure if it
  works on mono; run-test is broken in trunk. Verified under .NET).

svn path=/trunk/mcs/; revision=160341

mcs/class/System.ServiceModel.Web/System.ServiceModel.Channels/ChangeLog
mcs/class/System.ServiceModel.Web/System.ServiceModel.Channels/WebMessageEncoder.cs
mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/ChangeLog
mcs/class/System.ServiceModel.Web/System.ServiceModel.Dispatcher/WebMessageFormatter.cs
mcs/class/System.ServiceModel.Web/Test/System.ServiceModel.Description/ChangeLog
mcs/class/System.ServiceModel.Web/Test/System.ServiceModel.Description/WebHttpBehaviorTest.cs

index b6cdce477472c4f66b1a334c4438b64a26dc8c9c..53703ef5c1ab7c4513b5ec53aae140a81a104168 100644 (file)
@@ -1,3 +1,7 @@
+2010-07-14  Atsushi Enomoto  <atsushi@ximian.com>
+
+       * WebMessageEncoder.cs : support Raw message. Fixed bug #619542.
+
 2010-06-22  Atsushi Enomoto  <atsushi@ximian.com>
 
        * WebMessageEncodingBindingElement.cs : return MessageVersion in
index 45ce9448b9d34b3e7b61d2dae4dfdacfec233aa5..700ea9fab75d2770db012f53b9e932d7bc97e6e3 100644 (file)
@@ -30,6 +30,7 @@ using System.IO;
 using System.Net.Mime;
 using System.Runtime.Serialization.Json;
 using System.ServiceModel;
+using System.ServiceModel.Dispatcher;
 using System.Text;
 using System.Xml;
 
@@ -177,7 +178,16 @@ namespace System.ServiceModel.Channels
                                        message.WriteMessage (w);
                                break;
                        case WebContentFormat.Raw:
-                               throw new NotImplementedException ();
+                               var rmsg = (WebMessageFormatter.RawMessage) message;
+                               var src = rmsg.Stream;
+                               if (src == null) // null output
+                                       break;
+
+                               int len = 0;
+                               byte [] buffer = new byte [4096];
+                               while ((len = src.Read (buffer, 0, buffer.Length)) > 0)
+                                       stream.Write (buffer, 0, len);
+                               break;
                        case WebContentFormat.Default:
                                throw new SystemException ("INTERNAL ERROR: cannot determine content format");
                        }
index 96e6faa96f8a856a1356041e0eb0836c8655455d..0110de19f4d2824ffd9cc3b054b66cd88e354ef8 100644 (file)
@@ -1,3 +1,7 @@
+2010-07-14  Atsushi Enomoto  <atsushi@ximian.com>
+
+       * WebMessageFormatter.cs : add support for Raw format.
+
 2010-07-06  Atsushi Enomoto  <atsushi@ximian.com>
 
        * WebMessageFormatter.cs : add NET_2_1 profile build.
index 485e875832c13e7c31fbcaafa31cde1440a6932b..7d3180da0e7699b6bcb737a0032ddb66491315a3 100644 (file)
 using System;
 using System.Collections.Generic;
 using System.Globalization;
+using System.IO;
 using System.Reflection;
 using System.Runtime.Serialization;
 using System.Runtime.Serialization.Json;
 using System.ServiceModel;
 using System.ServiceModel.Channels;
-using System.ServiceModel.Dispatcher;
+using System.ServiceModel.Description;
 using System.ServiceModel.Web;
 using System.Text;
 using System.Xml;
@@ -42,7 +43,7 @@ using System.Xml;
 using XmlObjectSerializer = System.Object;
 #endif
 
-namespace System.ServiceModel.Description
+namespace System.ServiceModel.Dispatcher
 {
        internal abstract class WebMessageFormatter
        {
@@ -125,8 +126,10 @@ namespace System.ServiceModel.Description
                        get { return template; }
                }
 
-               protected WebContentFormat ToContentFormat (WebMessageFormat src)
+               protected WebContentFormat ToContentFormat (WebMessageFormat src, object result)
                {
+                       if (result is Stream)
+                               return WebContentFormat.Raw;
                        switch (src) {
                        case WebMessageFormat.Xml:
                                return WebContentFormat.Xml;
@@ -287,7 +290,7 @@ namespace System.ServiceModel.Description
                                // FIXME: set hp.SuppressEntityBody for some cases.
                                ret.Properties.Add (HttpRequestMessageProperty.Name, hp);
 
-                               var wp = new WebBodyFormatMessageProperty (ToContentFormat (Info.IsRequestFormatSetExplicitly ? Info.RequestFormat : Behavior.DefaultOutgoingRequestFormat));
+                               var wp = new WebBodyFormatMessageProperty (ToContentFormat (Info.IsRequestFormatSetExplicitly ? Info.RequestFormat : Behavior.DefaultOutgoingRequestFormat, null));
                                ret.Properties.Add (WebBodyFormatMessageProperty.Name, wp);
 
                                return ret;
@@ -336,17 +339,17 @@ namespace System.ServiceModel.Description
 
                internal class WrappedBodyWriter : BodyWriter
                {
-                       public WrappedBodyWriter (object value, XmlObjectSerializer serializer, string name, string ns, bool json)
+                       public WrappedBodyWriter (object value, XmlObjectSerializer serializer, string name, string ns, WebContentFormat fmt)
                                : base (true)
                        {
                                this.name = name;
                                this.ns = ns;
                                this.value = value;
                                this.serializer = serializer;
-                               this.is_json = json;
+                               this.fmt = fmt;
                        }
 
-                       bool is_json;
+                       WebContentFormat fmt;
                        string name, ns;
                        object value;
                        XmlObjectSerializer serializer;
@@ -354,16 +357,28 @@ namespace System.ServiceModel.Description
 #if !NET_2_1
                        protected override BodyWriter OnCreateBufferedCopy (int maxBufferSize)
                        {
-                               return new WrappedBodyWriter (value, serializer, name, ns, is_json);
+                               return new WrappedBodyWriter (value, serializer, name, ns, fmt);
                        }
 #endif
 
                        protected override void OnWriteBodyContents (XmlDictionaryWriter writer)
                        {
-                               if (is_json)
+                               switch (fmt) {
+                               case WebContentFormat.Raw:
+                                       WriteRawContents (writer);
+                                       break;
+                               case WebContentFormat.Json:
                                        WriteJsonBodyContents (writer);
-                               else
+                                       break;
+                               case WebContentFormat.Xml:
                                        WriteXmlBodyContents (writer);
+                                       break;
+                               }
+                       }
+                       
+                       void WriteRawContents (XmlDictionaryWriter writer)
+                       {
+                               throw new NotSupportedException ("Some unsupported sequence of writing operation occured. It is likely a missing feature.");
                        }
                        
                        void WriteJsonBodyContents (XmlDictionaryWriter writer)
@@ -419,8 +434,9 @@ namespace System.ServiceModel.Description
 
                        Message SerializeReplyCore (MessageVersion messageVersion, object [] parameters, object result)
                        {
-                               if (parameters == null)
-                                       throw new ArgumentNullException ("parameters");
+                               // parameters could be null.
+                               // result could be null. For Raw output, it becomes no output.
+
                                CheckMessageVersion (messageVersion);
 
                                MessageDescription md = GetMessageDescription (MessageDirection.Output);
@@ -455,8 +471,8 @@ namespace System.ServiceModel.Description
                                        break;
                                }
 
-                               bool json = msgfmt == WebMessageFormat.Json;
-                               Message ret = Message.CreateMessage (MessageVersion.None, null, new WrappedBodyWriter (result, serializer, name, ns, json));
+                               var contentFormat = ToContentFormat (msgfmt, result);
+                               Message ret = contentFormat == WebContentFormat.Raw ? new RawMessage ((Stream) result) : Message.CreateMessage (MessageVersion.None, null, new WrappedBodyWriter (result, serializer, name, ns, contentFormat));
 
                                // Message properties
 
@@ -465,12 +481,13 @@ namespace System.ServiceModel.Description
                                hp.Headers ["Content-Type"] = mediaType + "; charset=utf-8";
 
                                // apply user-customized HTTP results via WebOperationContext.
-                               WebOperationContext.Current.OutgoingResponse.Apply (hp);
+                               if (WebOperationContext.Current != null) // this formatter must be available outside ServiceHost.
+                                       WebOperationContext.Current.OutgoingResponse.Apply (hp);
 
                                // FIXME: fill some properties if required.
                                ret.Properties.Add (HttpResponseMessageProperty.Name, hp);
 
-                               var wp = new WebBodyFormatMessageProperty (ToContentFormat (msgfmt));
+                               var wp = new WebBodyFormatMessageProperty (contentFormat);
                                ret.Properties.Add (WebBodyFormatMessageProperty.Name, wp);
 
                                return ret;
@@ -504,5 +521,38 @@ namespace System.ServiceModel.Description
                        }
                }
 #endif
+
+               internal class RawMessage : Message
+               {
+                       public RawMessage (Stream stream)
+                       {
+                               this.Stream = stream;
+                               headers = new MessageHeaders (MessageVersion.None);
+                               properties = new MessageProperties ();
+                       }
+               
+                       public override MessageVersion Version {
+                               get { return MessageVersion.None; }
+                       }
+               
+                       MessageHeaders headers;
+
+                       public override MessageHeaders Headers {
+                               get { return headers; }
+                       }
+               
+                       MessageProperties properties;
+
+                       public override MessageProperties Properties {
+                               get { return properties; }
+                       }
+
+                       public Stream Stream { get; private set; }
+
+                       protected override void OnWriteBodyContents (XmlDictionaryWriter writer)
+                       {
+                               throw new NotSupportedException ();
+                       }
+               }
        }
 }
index ba7c2d280d625315aa01af44cd336e50ca120ae2..6c2a20b9bfac22b0787306795547fc619f81a105 100644 (file)
@@ -1,3 +1,8 @@
+2010-07-14  Atsushi Enomoto  <atsushi@ximian.com>
+
+       * WebHttpBehaviorTest.cs : add test for bug #619542 (not sure if it
+         works on mono; run-test is broken in trunk. Verified under .NET).
+
 2009-10-08  Atsushi Enomoto  <atsushi@ximian.com>
 
        * WebScriptEnablingBehaviorTest.cs : new test.
index d7ebd9a8858764576ed3b5afb9cc8335659d5c61..009ba909588b97c5ce13553181b2570306bcaaab 100644 (file)
@@ -1,4 +1,5 @@
 using System;
+using System.IO;
 using System.Runtime.Serialization;
 using System.ServiceModel;
 using System.ServiceModel.Channels;
@@ -188,5 +189,36 @@ namespace MonoTests.System.ServiceModel.Description
                        OperationDescription od = cd.Operations[0];
                        Assert.IsTrue (od.Behaviors.Contains (typeof (WebGetAttribute)), "Operation is recognized as WebGet");
                }
+
+               [Test]
+               public void MessageFormatterSupportsRaw ()
+               {
+                       var ms = new MemoryStream ();
+                       var bytes = new byte [] {0, 1, 2, 0xFF};
+                       ms.Write (bytes, 0, bytes.Length);
+                       ms.Position = 0;
+                       var cd = ContractDescription.GetContract (typeof (ITestService));
+                       var od = cd.Operations [0];
+                       var se = new ServiceEndpoint (cd, new WebHttpBinding (), new EndpointAddress ("http://localhost:37564/"));
+                       var formatter = new WebHttpBehaviorExt ().DoGetReplyDispatchFormatter (od, se);
+
+                       var msg = formatter.SerializeReply (MessageVersion.None, null, ms);
+                       var wp = msg.Properties ["WebBodyFormatMessageProperty"] as WebBodyFormatMessageProperty;
+                       Assert.IsNotNull (wp, "#1");
+                       Assert.AreEqual (WebContentFormat.Raw, wp.Format, "#2");
+
+                       var wmebe = new WebMessageEncodingBindingElement ();
+                       var wme = wmebe.CreateMessageEncoderFactory ().Encoder;
+                       var ms2 = new MemoryStream ();
+                       wme.WriteMessage (msg, ms2);
+                       Assert.AreEqual (bytes, ms2.ToArray (), "#3");
+               }
+       }
+
+       [ServiceContract]
+       public interface ITestService
+       {
+               [OperationContract]
+               Stream Receive (Stream input);
        }
 }