2 // WebMessageEncoder.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2008 Novell, Inc (http://www.novell.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Runtime.Serialization.Json;
31 using System.ServiceModel;
32 using System.ServiceModel.Dispatcher;
36 namespace System.ServiceModel.Channels
38 internal class WebMessageEncoder : MessageEncoder
40 internal const string ScriptPropertyName = "618BC2B0-38AA-21A3-DB4A-404FC87B9B11"; // randomly generated
42 WebMessageEncodingBindingElement source;
44 public WebMessageEncoder (WebMessageEncodingBindingElement source)
49 public override string ContentType {
51 get { return MediaType; }
53 get { return MediaType + "; charset=" + source.WriteEncoding.HeaderName; }
57 // FIXME: find out how it can be customized.
58 public override string MediaType {
59 get { return "application/xml"; }
62 public override MessageVersion MessageVersion {
63 get { return MessageVersion.None; }
66 public override bool IsContentTypeSupported (string contentType)
68 if (contentType == null)
69 throw new ArgumentNullException ("contentType");
70 return true; // anything is accepted.
73 public override Message ReadMessage (ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
75 throw new NotImplementedException ();
78 public override Message ReadMessage (Stream stream, int maxSizeOfHeaders, string contentType)
81 throw new ArgumentNullException ("stream");
83 contentType = contentType ?? "application/octet-stream";
85 Encoding enc = Encoding.UTF8;
86 var ct = new System.Net.Mime.ContentType (contentType);
87 if (ct.CharSet != null)
88 enc = Encoding.GetEncoding (ct.CharSet);
90 WebContentFormat fmt = WebContentFormat.Xml;
91 if (source.ContentTypeMapper != null)
92 fmt = source.ContentTypeMapper.GetMessageFormatForContentType (contentType);
94 switch (ct.MediaType) {
95 case "application/json":
96 fmt = WebContentFormat.Json;
98 case "application/xml":
99 fmt = WebContentFormat.Xml;
102 fmt = WebContentFormat.Raw;
108 WebBodyFormatMessageProperty wp = null;
110 case WebContentFormat.Xml:
111 // FIXME: is it safe/unsafe/required to keep XmlReader open?
112 msg = Message.CreateMessage (MessageVersion.None, null, XmlReader.Create (new StreamReader (stream, enc)));
113 wp = new WebBodyFormatMessageProperty (WebContentFormat.Xml);
115 case WebContentFormat.Json:
116 // FIXME: is it safe/unsafe/required to keep XmlReader open?
118 msg = Message.CreateMessage (MessageVersion.None, null, JsonReaderWriterFactory.CreateJsonReader (stream, source.ReaderQuotas));
120 msg = Message.CreateMessage (MessageVersion.None, null, JsonReaderWriterFactory.CreateJsonReader (stream, enc, source.ReaderQuotas, null));
122 wp = new WebBodyFormatMessageProperty (WebContentFormat.Json);
124 case WebContentFormat.Raw:
125 msg = new WebMessageFormatter.RawMessage (stream);
126 wp = new WebBodyFormatMessageProperty (WebContentFormat.Raw);
129 throw new SystemException ("INTERNAL ERROR: cannot determine content format");
132 msg.Properties.Add (WebBodyFormatMessageProperty.Name, wp);
133 msg.Properties.Encoder = this;
137 WebContentFormat GetContentFormat (Message message)
139 string name = WebBodyFormatMessageProperty.Name;
140 if (message.Properties.ContainsKey (name))
141 return ((WebBodyFormatMessageProperty) message.Properties [name]).Format;
144 case "application/xml":
146 return WebContentFormat.Xml;
147 case "application/json":
149 return WebContentFormat.Json;
150 case "application/octet-stream":
151 return WebContentFormat.Raw;
153 return WebContentFormat.Default;
157 public override void WriteMessage (Message message, Stream stream)
160 throw new ArgumentNullException ("message");
162 // Handle /js and /jsdebug as the special cases.
163 var script = message.Properties [ScriptPropertyName] as string;
164 if (script != null) {
165 var bytes = source.WriteEncoding.GetBytes (script);
166 stream.Write (bytes, 0, bytes.Length);
170 if (!MessageVersion.Equals (message.Version))
171 throw new ProtocolException (String.Format ("MessageVersion {0} is not supported", message.Version));
173 throw new ArgumentNullException ("stream");
175 switch (GetContentFormat (message)) {
176 case WebContentFormat.Xml:
178 using (XmlWriter w = XmlDictionaryWriter.CreateDictionaryWriter (XmlWriter.Create (new StreamWriter (stream, source.WriteEncoding))))
179 message.WriteMessage (w);
181 using (XmlWriter w = XmlDictionaryWriter.CreateTextWriter (stream, source.WriteEncoding, false))
182 message.WriteMessage (w);
185 case WebContentFormat.Json:
186 using (XmlWriter w = JsonReaderWriterFactory.CreateJsonWriter (stream, source.WriteEncoding, false))
187 message.WriteMessage (w);
189 case WebContentFormat.Raw:
190 var rmsg = (WebMessageFormatter.RawMessage) message;
191 var src = rmsg.Stream;
192 if (src == null) // null output
196 byte [] buffer = new byte [4096];
197 while ((len = src.Read (buffer, 0, buffer.Length)) > 0)
198 stream.Write (buffer, 0, len);
200 case WebContentFormat.Default:
201 throw new SystemException ("INTERNAL ERROR: cannot determine content format");
205 public override ArraySegment<byte> WriteMessage (Message message, int maxMessageSize, BufferManager bufferManager,
208 throw new NotImplementedException ();