5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2005-2006,2010 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.
29 using System.Collections.Generic;
31 using System.Runtime.Serialization;
33 using System.Xml.Schema;
36 namespace System.ServiceModel.Channels
38 public abstract class Message : IDisposable
42 Message copied_message;
45 protected Message () {
46 State = MessageState.Created;
49 public abstract MessageHeaders Headers { get; }
51 public virtual bool IsEmpty {
55 public virtual bool IsFault {
59 public abstract MessageProperties Properties { get; }
61 public MessageState State { get; private set; }
63 public abstract MessageVersion Version { get; }
65 protected bool IsDisposed {
66 get { return disposed; }
73 State = MessageState.Closed;
77 public MessageBuffer CreateBufferedCopy (int maxBufferSize)
79 if (State != MessageState.Created)
80 throw new InvalidOperationException (String.Format ("The message is already at {0} state", State));
82 if (copied_message != null)
83 return copied_message.CreateBufferedCopy (maxBufferSize);
86 return OnCreateBufferedCopy (maxBufferSize);
88 State = MessageState.Copied;
92 void IDisposable.Dispose ()
97 public T GetBody<T> ()
99 return OnGetBody<T> (GetReaderAtBodyContents ());
102 public T GetBody<T> (XmlObjectSerializer xmlFormatter)
104 // FIXME: Somehow use OnGetBody() here as well?
105 return (T)xmlFormatter.ReadObject (GetReaderAtBodyContents ());
108 protected virtual T OnGetBody<T> (XmlDictionaryReader reader)
110 var xmlFormatter = new DataContractSerializer (typeof (T));
111 return (T)xmlFormatter.ReadObject (reader);
114 public string GetBodyAttribute (string localName, string ns)
116 return OnGetBodyAttribute (localName, ns);
119 public XmlDictionaryReader GetReaderAtBodyContents ()
121 if (copied_message != null)
122 return copied_message.GetReaderAtBodyContents ();
124 return OnGetReaderAtBodyContents ();
127 public override string ToString ()
129 if (string_cache != null)
132 StringWriter sw = new StringWriter ();
133 XmlWriterSettings settings = new XmlWriterSettings ();
134 settings.Indent = true;
135 settings.OmitXmlDeclaration = true;
137 using (XmlWriter w = XmlWriter.Create (sw, settings)) {
138 OnBodyToString (XmlDictionaryWriter.CreateDictionaryWriter (w));
140 string_cache = sw.ToString ();
144 void WriteXsiNil (XmlDictionaryWriter writer)
146 var dic = Constants.SoapDictionary;
147 writer.WriteStartElement ("z", dic.Add ("anyType"), dic.Add (Constants.MSSerialization));
148 writer.WriteAttributeString ("i", dic.Add ("nil"), dic.Add ("http://www.w3.org/2001/XMLSchema-instance"), "true");
149 writer.WriteEndElement ();
152 public void WriteBody (XmlDictionaryWriter writer)
154 if (Version.Envelope != EnvelopeVersion.None)
155 WriteStartBody (writer);
156 WriteBodyContents (writer);
157 if (Version.Envelope != EnvelopeVersion.None)
158 writer.WriteEndElement ();
161 public void WriteBody (XmlWriter writer)
163 WriteBody (XmlDictionaryWriter.CreateDictionaryWriter (writer));
166 public void WriteBodyContents (XmlDictionaryWriter writer)
169 if (copied_message != null)
170 copied_message.WriteBodyContents (writer);
172 OnWriteBodyContents (writer);
174 else if (Version.Envelope == EnvelopeVersion.None)
175 WriteXsiNil (writer);
176 State = MessageState.Written;
179 public void WriteMessage (XmlDictionaryWriter writer)
181 if (State != MessageState.Created)
182 throw new InvalidOperationException (String.Format ("The message is already at {0} state", State));
184 OnWriteMessage (writer);
187 public void WriteMessage (XmlWriter writer)
189 WriteMessage (XmlDictionaryWriter.CreateDictionaryWriter (writer));
192 public void WriteStartBody (XmlDictionaryWriter writer)
194 if (State != MessageState.Created)
195 throw new InvalidOperationException (String.Format ("The message is already at {0} state", State));
197 OnWriteStartBody (writer);
200 public void WriteStartBody (XmlWriter writer)
203 XmlDictionaryWriter.CreateDictionaryWriter (writer));
206 public void WriteStartEnvelope (XmlDictionaryWriter writer)
208 if (State != MessageState.Created)
209 throw new InvalidOperationException (String.Format ("The message is already at {0} state", State));
211 OnWriteStartEnvelope (writer);
214 protected virtual void OnBodyToString (
215 XmlDictionaryWriter writer)
217 MessageState tempState = State;
219 var mb = CreateBufferedCopy (int.MaxValue);
220 copied_message = mb.CreateMessage ();
221 var msg = mb.CreateMessage ();
222 msg.WriteMessage (writer);
229 protected virtual void OnClose ()
233 protected virtual MessageBuffer OnCreateBufferedCopy (
236 var s = new XmlWriterSettings ();
237 s.OmitXmlDeclaration = true;
238 s.ConformanceLevel = ConformanceLevel.Auto;
239 StringWriter sw = new StringWriter ();
240 using (XmlDictionaryWriter w = XmlDictionaryWriter.CreateDictionaryWriter (XmlWriter.Create (sw, s)))
241 WriteBodyContents (w);
242 var headers = new MessageHeaders (Headers);
243 var props = new MessageProperties (Properties);
244 return new DefaultMessageBuffer (maxBufferSize, headers, props, new XmlReaderBodyWriter (sw.ToString (), maxBufferSize, null), false, new AttributeCollection ());
247 protected virtual string OnGetBodyAttribute (
248 string localName, string ns)
253 protected virtual XmlDictionaryReader OnGetReaderAtBodyContents ()
255 var ws = new XmlWriterSettings ();
256 ws.ConformanceLevel = ConformanceLevel.Auto;
257 StringWriter sw = new StringWriter ();
258 using (XmlDictionaryWriter body = XmlDictionaryWriter.CreateDictionaryWriter (XmlWriter.Create (sw, ws))) {
259 WriteBodyContents (body);
262 var rs = new XmlReaderSettings ();
263 rs.ConformanceLevel = ConformanceLevel.Auto;
264 return XmlDictionaryReader.CreateDictionaryReader (XmlReader.Create (new StringReader (sw.ToString ()), rs));
267 protected abstract void OnWriteBodyContents (
268 XmlDictionaryWriter writer);
270 protected virtual void OnWriteMessage (
271 XmlDictionaryWriter writer)
273 if (Version.Envelope != EnvelopeVersion.None) {
274 WriteStartEnvelope (writer);
275 if (Headers.Count > 0) {
276 OnWriteStartHeaders (writer);
277 for (int i = 0, count = Headers.Count; i < count; i++)
278 Headers.WriteHeader (i, writer);
279 writer.WriteEndElement ();
283 if (Version.Envelope != EnvelopeVersion.None)
284 writer.WriteEndElement ();
287 protected virtual void OnWriteStartBody (
288 XmlDictionaryWriter writer)
290 var dic = Constants.SoapDictionary;
291 writer.WriteStartElement ("s", dic.Add ("Body"), dic.Add (Version.Envelope.Namespace));
294 protected virtual void OnWriteStartEnvelope (
295 XmlDictionaryWriter writer)
297 var dic = Constants.SoapDictionary;
298 writer.WriteStartElement ("s", dic.Add ("Envelope"), dic.Add (Version.Envelope.Namespace));
299 if (Headers.Action != null && Version.Addressing.Namespace != MessageVersion.None.Addressing.Namespace)
300 writer.WriteXmlnsAttribute ("a", dic.Add (Version.Addressing.Namespace));
301 foreach (MessageHeaderInfo h in Headers)
302 if (h.Id != null && writer.LookupPrefix (Constants.WsuNamespace) != "u") {
303 writer.WriteXmlnsAttribute ("u", dic.Add (Constants.WsuNamespace));
308 protected virtual void OnWriteStartHeaders (
309 XmlDictionaryWriter writer)
311 var dic = Constants.SoapDictionary;
312 writer.WriteStartElement ("s", dic.Add ("Header"), dic.Add (Version.Envelope.Namespace));
315 #region factory methods
317 // 1) version, code, reason, action -> 3
318 // 2) version, code, reason, detail, action -> 3
319 // 3) version, fault, action -> SimpleMessage
320 // 4) version, action, body -> 10 or 5
321 // 5) version, action, body, formatter -> 10 or 9
322 // 6) version, action, xmlReader -> 7
323 // 7) version, action, reader -> 9
324 // 8) xmlReader, maxSizeOfHeaders, version -> 11
325 // 9) version, action, body -> SimpleMessage
326 // 10) version, action -> EmptyMessage
327 // 11) reader, maxSizeOfHeaders, version -> XmlReaderMessage
330 public static Message CreateMessage (MessageVersion version,
331 FaultCode code, string reason, string action)
333 MessageFault fault = MessageFault.CreateFault (code, reason);
334 return CreateMessage (version, fault, action);
338 public static Message CreateMessage (MessageVersion version,
339 FaultCode code, string reason, object detail,
342 MessageFault fault = MessageFault.CreateFault (
343 code, new FaultReason (reason), detail);
344 return CreateMessage (version, fault, action);
348 public static Message CreateMessage (MessageVersion version,
349 MessageFault fault, string action)
351 return new SimpleMessage (version, action,
352 new MessageFaultBodyWriter (fault, version), true, empty_attributes);
356 public static Message CreateMessage (MessageVersion version,
357 string action, object body)
359 return body == null ?
360 CreateMessage (version, action) :
361 CreateMessage (version, action, body, new DataContractSerializer (body.GetType ()));
365 public static Message CreateMessage (MessageVersion version,
366 string action, object body, XmlObjectSerializer xmlFormatter)
368 return body == null ?
369 CreateMessage (version, action) :
372 new XmlObjectSerializerBodyWriter (body, xmlFormatter));
376 public static Message CreateMessage (MessageVersion version,
377 string action, XmlReader body)
379 return CreateMessage (version, action,
380 XmlDictionaryReader.CreateDictionaryReader (body));
384 public static Message CreateMessage (MessageVersion version,
385 string action, XmlDictionaryReader body)
387 return CreateMessage (version, action,
388 new XmlReaderBodyWriter (body));
392 public static Message CreateMessage (XmlReader envelopeReader,
393 int maxSizeOfHeaders, MessageVersion version)
395 return CreateMessage (
396 XmlDictionaryReader.CreateDictionaryReader (envelopeReader),
401 // Core implementations of CreateMessage.
403 static readonly AttributeCollection empty_attributes = new AttributeCollection ();
406 public static Message CreateMessage (MessageVersion version,
407 string action, BodyWriter body)
410 throw new ArgumentNullException ("version");
412 throw new ArgumentNullException ("body");
413 return new SimpleMessage (version, action, body, false, empty_attributes);
417 public static Message CreateMessage (MessageVersion version,
421 throw new ArgumentNullException ("version");
422 return new EmptyMessage (version, action);
426 public static Message CreateMessage (
427 XmlDictionaryReader envelopeReader,
428 int maxSizeOfHeaders,
429 MessageVersion version)
431 if (envelopeReader == null)
432 throw new ArgumentNullException ("envelopeReader");
434 throw new ArgumentNullException ("version");
435 return new XmlReaderMessage (version,
436 envelopeReader, maxSizeOfHeaders);