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
;
35 namespace System
.ServiceModel
.Channels
37 public abstract class Message
: IDisposable
41 Message copied_message
;
44 protected Message () {
45 State
= MessageState
.Created
;
48 public abstract MessageHeaders Headers { get; }
50 public virtual bool IsEmpty
{
54 public virtual bool IsFault
{
58 public abstract MessageProperties Properties { get; }
60 public MessageState State { get; private set; }
62 public abstract MessageVersion Version { get; }
64 protected bool IsDisposed
{
65 get { return disposed; }
72 State
= MessageState
.Closed
;
76 public MessageBuffer
CreateBufferedCopy (int maxBufferSize
)
78 if (State
!= MessageState
.Created
)
79 throw new InvalidOperationException (String
.Format ("The message is already at {0} state", State
));
81 if (copied_message
!= null)
82 return copied_message
.CreateBufferedCopy (maxBufferSize
);
85 return OnCreateBufferedCopy (maxBufferSize
);
87 State
= MessageState
.Copied
;
91 void IDisposable
.Dispose ()
96 public T GetBody
<T
> ()
98 return OnGetBody
<T
> (GetReaderAtBodyContents ());
101 public T GetBody
<T
> (XmlObjectSerializer serializer
)
103 // FIXME: Somehow use OnGetBody() here as well?
104 return (T
)serializer
.ReadObject (GetReaderAtBodyContents ());
107 protected virtual T OnGetBody
<T
> (XmlDictionaryReader reader
)
109 var xmlFormatter
= new DataContractSerializer (typeof (T
));
110 return (T
)xmlFormatter
.ReadObject (reader
);
113 public string GetBodyAttribute (string localName
, string ns
)
115 return OnGetBodyAttribute (localName
, ns
);
118 public XmlDictionaryReader
GetReaderAtBodyContents ()
120 if (copied_message
!= null)
121 return copied_message
.GetReaderAtBodyContents ();
123 return OnGetReaderAtBodyContents ();
126 public override string ToString ()
128 if (string_cache
!= null)
131 StringWriter sw
= new StringWriter ();
132 XmlWriterSettings settings
= new XmlWriterSettings ();
133 settings
.Indent
= true;
134 settings
.OmitXmlDeclaration
= true;
136 using (XmlWriter w
= XmlWriter
.Create (sw
, settings
)) {
137 OnBodyToString (XmlDictionaryWriter
.CreateDictionaryWriter (w
));
139 string_cache
= sw
.ToString ();
143 void WriteXsiNil (XmlDictionaryWriter writer
)
145 var dic
= Constants
.SoapDictionary
;
146 writer
.WriteStartElement ("z", dic
.Add ("anyType"), dic
.Add (Constants
.MSSerialization
));
147 writer
.WriteAttributeString ("i", dic
.Add ("nil"), dic
.Add ("http://www.w3.org/2001/XMLSchema-instance"), "true");
148 writer
.WriteEndElement ();
151 public void WriteBody (XmlDictionaryWriter writer
)
153 if (Version
.Envelope
!= EnvelopeVersion
.None
)
154 WriteStartBody (writer
);
155 WriteBodyContents (writer
);
156 if (Version
.Envelope
!= EnvelopeVersion
.None
)
157 writer
.WriteEndElement ();
160 public void WriteBody (XmlWriter writer
)
162 WriteBody (XmlDictionaryWriter
.CreateDictionaryWriter (writer
));
165 public void WriteBodyContents (XmlDictionaryWriter writer
)
168 if (copied_message
!= null)
169 copied_message
.WriteBodyContents (writer
);
171 OnWriteBodyContents (writer
);
173 else if (Version
.Envelope
== EnvelopeVersion
.None
)
174 WriteXsiNil (writer
);
175 State
= MessageState
.Written
;
178 public void WriteMessage (XmlDictionaryWriter writer
)
180 if (State
!= MessageState
.Created
)
181 throw new InvalidOperationException (String
.Format ("The message is already at {0} state", State
));
183 OnWriteMessage (writer
);
186 public void WriteMessage (XmlWriter writer
)
188 WriteMessage (XmlDictionaryWriter
.CreateDictionaryWriter (writer
));
191 public void WriteStartBody (XmlDictionaryWriter writer
)
193 if (State
!= MessageState
.Created
)
194 throw new InvalidOperationException (String
.Format ("The message is already at {0} state", State
));
196 OnWriteStartBody (writer
);
199 public void WriteStartBody (XmlWriter writer
)
202 XmlDictionaryWriter
.CreateDictionaryWriter (writer
));
205 public void WriteStartEnvelope (XmlDictionaryWriter writer
)
207 if (State
!= MessageState
.Created
)
208 throw new InvalidOperationException (String
.Format ("The message is already at {0} state", State
));
210 OnWriteStartEnvelope (writer
);
213 protected virtual void OnBodyToString (
214 XmlDictionaryWriter writer
)
216 MessageState tempState
= State
;
218 var mb
= CreateBufferedCopy (int.MaxValue
);
219 copied_message
= mb
.CreateMessage ();
220 var msg
= mb
.CreateMessage ();
221 msg
.WriteMessage (writer
);
228 protected virtual void OnClose ()
232 protected virtual MessageBuffer
OnCreateBufferedCopy (
235 var s
= new XmlWriterSettings ();
236 s
.OmitXmlDeclaration
= true;
237 s
.ConformanceLevel
= ConformanceLevel
.Auto
;
238 StringWriter sw
= new StringWriter ();
239 using (XmlDictionaryWriter w
= XmlDictionaryWriter
.CreateDictionaryWriter (XmlWriter
.Create (sw
, s
)))
240 WriteBodyContents (w
);
241 var headers
= new MessageHeaders (Headers
);
242 var props
= new MessageProperties (Properties
);
243 return new DefaultMessageBuffer (maxBufferSize
, headers
, props
, new XmlReaderBodyWriter (sw
.ToString (), maxBufferSize
, null), false, new AttributeCollection ());
246 protected virtual string OnGetBodyAttribute (
247 string localName
, string ns
)
252 protected virtual XmlDictionaryReader
OnGetReaderAtBodyContents ()
254 var ws
= new XmlWriterSettings ();
255 ws
.ConformanceLevel
= ConformanceLevel
.Auto
;
256 StringWriter sw
= new StringWriter ();
257 using (XmlDictionaryWriter body
= XmlDictionaryWriter
.CreateDictionaryWriter (XmlWriter
.Create (sw
, ws
))) {
258 WriteBodyContents (body
);
261 var nt
= new NameTable ();
262 var nsmgr
= new XmlNamespaceManager (nt
);
263 nsmgr
.AddNamespace ("s", Version
.Envelope
.Namespace
);
264 nsmgr
.AddNamespace ("a", Version
.Addressing
.Namespace
);
265 var pc
= new XmlParserContext (nt
, nsmgr
, null, XmlSpace
.None
);
267 var rs
= new XmlReaderSettings ();
268 rs
.ConformanceLevel
= ConformanceLevel
.Auto
;
270 return XmlDictionaryReader
.CreateDictionaryReader (XmlReader
.Create (new StringReader (sw
.ToString ()), rs
, pc
));
273 protected abstract void OnWriteBodyContents (
274 XmlDictionaryWriter writer
);
276 protected virtual void OnWriteMessage (
277 XmlDictionaryWriter writer
)
279 if (Version
.Envelope
!= EnvelopeVersion
.None
) {
280 WriteStartEnvelope (writer
);
281 if (Headers
.Count
> 0) {
282 OnWriteStartHeaders (writer
);
283 for (int i
= 0, count
= Headers
.Count
; i
< count
; i
++)
284 Headers
.WriteHeader (i
, writer
);
285 writer
.WriteEndElement ();
289 if (Version
.Envelope
!= EnvelopeVersion
.None
)
290 writer
.WriteEndElement ();
293 protected virtual void OnWriteStartBody (
294 XmlDictionaryWriter writer
)
296 var dic
= Constants
.SoapDictionary
;
297 writer
.WriteStartElement ("s", dic
.Add ("Body"), dic
.Add (Version
.Envelope
.Namespace
));
300 protected virtual void OnWriteStartEnvelope (
301 XmlDictionaryWriter writer
)
303 var dic
= Constants
.SoapDictionary
;
304 writer
.WriteStartElement ("s", dic
.Add ("Envelope"), dic
.Add (Version
.Envelope
.Namespace
));
305 if (Headers
.Action
!= null && Version
.Addressing
.Namespace
!= MessageVersion
.None
.Addressing
.Namespace
)
306 writer
.WriteXmlnsAttribute ("a", dic
.Add (Version
.Addressing
.Namespace
));
307 foreach (MessageHeaderInfo h
in Headers
)
308 if (h
.Id
!= null && writer
.LookupPrefix (Constants
.WsuNamespace
) != "u") {
309 writer
.WriteXmlnsAttribute ("u", dic
.Add (Constants
.WsuNamespace
));
314 protected virtual void OnWriteStartHeaders (
315 XmlDictionaryWriter writer
)
317 var dic
= Constants
.SoapDictionary
;
318 writer
.WriteStartElement ("s", dic
.Add ("Header"), dic
.Add (Version
.Envelope
.Namespace
));
321 #region factory methods
323 // 1) version, code, reason, action -> 3
324 // 2) version, code, reason, detail, action -> 3
325 // 3) version, fault, action -> SimpleMessage
326 // 4) version, action, body -> 10 or 5
327 // 5) version, action, body, formatter -> 10 or 9
328 // 6) version, action, xmlReader -> 7
329 // 7) version, action, reader -> 9
330 // 8) xmlReader, maxSizeOfHeaders, version -> 11
331 // 9) version, action, body -> SimpleMessage
332 // 10) version, action -> EmptyMessage
333 // 11) reader, maxSizeOfHeaders, version -> XmlReaderMessage
336 public static Message
CreateMessage (MessageVersion version
,
337 FaultCode faultCode
, string reason
, string action
)
339 MessageFault fault
= MessageFault
.CreateFault (faultCode
, reason
);
340 return CreateMessage (version
, fault
, action
);
344 public static Message
CreateMessage (MessageVersion version
,
345 FaultCode faultCode
, string reason
, object detail
,
348 MessageFault fault
= MessageFault
.CreateFault (
349 faultCode
, new FaultReason (reason
), detail
);
350 return CreateMessage (version
, fault
, action
);
354 public static Message
CreateMessage (MessageVersion version
,
355 MessageFault fault
, string action
)
357 return new SimpleMessage (version
, action
,
358 new MessageFaultBodyWriter (fault
, version
), true, empty_attributes
);
362 public static Message
CreateMessage (MessageVersion version
,
363 string action
, object body
)
365 return body
== null ?
366 CreateMessage (version
, action
) :
367 CreateMessage (version
, action
, body
, new DataContractSerializer (body
.GetType ()));
371 public static Message
CreateMessage (MessageVersion version
,
372 string action
, object body
, XmlObjectSerializer serializer
)
374 return body
== null ?
375 CreateMessage (version
, action
) :
378 new XmlObjectSerializerBodyWriter (body
, serializer
));
382 public static Message
CreateMessage (MessageVersion version
,
383 string action
, XmlReader body
)
385 return CreateMessage (version
, action
,
386 XmlDictionaryReader
.CreateDictionaryReader (body
));
390 public static Message
CreateMessage (MessageVersion version
,
391 string action
, XmlDictionaryReader body
)
393 return CreateMessage (version
, action
,
394 new XmlReaderBodyWriter (body
));
398 public static Message
CreateMessage (XmlReader envelopeReader
,
399 int maxSizeOfHeaders
, MessageVersion version
)
401 return CreateMessage (
402 XmlDictionaryReader
.CreateDictionaryReader (envelopeReader
),
407 // Core implementations of CreateMessage.
409 static readonly AttributeCollection empty_attributes
= new AttributeCollection ();
412 public static Message
CreateMessage (MessageVersion version
,
413 string action
, BodyWriter body
)
416 throw new ArgumentNullException ("version");
418 throw new ArgumentNullException ("body");
419 return new SimpleMessage (version
, action
, body
, false, empty_attributes
);
423 public static Message
CreateMessage (MessageVersion version
,
427 throw new ArgumentNullException ("version");
428 return new EmptyMessage (version
, action
);
432 public static Message
CreateMessage (
433 XmlDictionaryReader envelopeReader
,
434 int maxSizeOfHeaders
,
435 MessageVersion version
)
437 if (envelopeReader
== null)
438 throw new ArgumentNullException ("envelopeReader");
440 throw new ArgumentNullException ("version");
441 return new XmlReaderMessage (version
,
442 envelopeReader
, maxSizeOfHeaders
);