2 // System.ServiceModel.MessageHeader.cs
4 // Author: Duncan Mak (duncan@novell.com)
5 // Atsushi Enomoto (atsushi@ximian.com)
7 // Copyright (C) 2005 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.
31 using System.Runtime.Serialization;
32 using System.ServiceModel;
33 using System.ServiceModel.Channels;
37 namespace System.ServiceModel.Channels
39 public abstract class MessageHeader : MessageHeaderInfo
41 static readonly XmlWriterSettings writer_settings;
43 static MessageHeader ()
45 writer_settings = new XmlWriterSettings ();
46 writer_settings.OmitXmlDeclaration = true;
47 writer_settings.Indent = true;
50 protected MessageHeader () {}
52 static string default_actor = String.Empty;
53 static bool default_is_ref = false;
54 static bool default_must_understand = false;
55 static bool default_relay = false;
57 public static MessageHeader CreateHeader (string name, string ns, object value)
59 return CreateHeader (name, ns, value, default_must_understand);
62 public static MessageHeader CreateHeader (string name, string ns, object value, bool mustUnderstand)
64 return CreateHeader (name, ns, value, mustUnderstand, default_actor);
67 public static MessageHeader CreateHeader (string name, string ns, object value, XmlObjectSerializer serializer)
69 return CreateHeader (name, ns, value, serializer, default_must_understand,
70 default_actor, default_relay);
73 public static MessageHeader CreateHeader (string name, string ns, object value,
74 bool mustUnderstand, string actor)
76 return CreateHeader (name, ns, value, mustUnderstand, actor, default_relay);
79 public static MessageHeader CreateHeader (string name, string ns, object value, XmlObjectSerializer serializer,
82 return CreateHeader (name, ns, value, serializer, mustUnderstand, default_actor, default_relay);
85 public static MessageHeader CreateHeader (string name, string ns, object value,
86 bool mustUnderstand, string actor, bool relay)
88 return CreateHeader (name, ns, value, new DataContractSerializer (value.GetType ()),
89 mustUnderstand, actor, relay);
92 public static MessageHeader CreateHeader (string name, string ns, object value, XmlObjectSerializer serializer,
93 bool mustUnderstand, string actor)
95 return CreateHeader (name, ns, value, serializer, mustUnderstand, actor, default_relay);
98 public static MessageHeader CreateHeader (string name, string ns, object value, XmlObjectSerializer serializer,
99 bool mustUnderstand, string actor, bool relay)
101 // FIXME: how to get IsReferenceParameter ?
102 return new DefaultMessageHeader (name, ns, value, serializer, default_is_ref, mustUnderstand, actor, relay);
105 public virtual bool IsMessageVersionSupported (MessageVersion messageVersion)
107 if (messageVersion.Envelope == EnvelopeVersion.Soap12)
108 if (Actor == EnvelopeVersion.Soap11.NextDestinationActorValue)
111 if (messageVersion.Envelope == EnvelopeVersion.Soap11)
112 if (Actor == EnvelopeVersion.Soap12.NextDestinationActorValue ||
113 Actor == EnvelopeVersion.Soap12UltimateReceiver)
116 // by default, it's always supported
120 protected abstract void OnWriteHeaderContents (XmlDictionaryWriter writer, MessageVersion messageVersion);
122 protected virtual void OnWriteStartHeader (XmlDictionaryWriter writer, MessageVersion messageVersion)
124 var dic = Constants.SoapDictionary;
125 XmlDictionaryString name, ns;
126 var prefix = Prefix ?? (Namespace.Length > 0 ? writer.LookupPrefix (Namespace) : String.Empty);
127 if (dic.TryLookup (Name, out name) && dic.TryLookup (Namespace, out ns))
128 writer.WriteStartElement (prefix, name, ns);
130 writer.WriteStartElement (prefix, this.Name, this.Namespace);
131 WriteHeaderAttributes (writer, messageVersion);
134 public override string ToString ()
136 StringBuilder sb = new StringBuilder ();
138 XmlWriter w = XmlWriter.Create (sb, writer_settings);
140 WriteHeader (w, MessageVersion.Default);
143 return sb.ToString ();
146 public void WriteHeader (XmlDictionaryWriter writer, MessageVersion messageVersion)
149 throw new ArgumentNullException ("writer is null.");
151 if (messageVersion == null)
152 throw new ArgumentNullException ("messageVersion is null.");
154 if (messageVersion.Envelope == EnvelopeVersion.None)
157 WriteStartHeader (writer, messageVersion);
158 WriteHeaderContents (writer, messageVersion);
160 writer.WriteEndElement ();
163 public void WriteHeader (XmlWriter writer, MessageVersion messageVersion)
165 WriteHeader (XmlDictionaryWriter.CreateDictionaryWriter (writer), messageVersion);
168 protected void WriteHeaderAttributes (XmlDictionaryWriter writer, MessageVersion messageVersion)
170 var dic = Constants.SoapDictionary;
172 writer.WriteAttributeString ("u", dic.Add ("Id"), dic.Add (Constants.WsuNamespace), Id);
173 if (!String.IsNullOrEmpty (Actor)) {
174 if (messageVersion.Envelope == EnvelopeVersion.Soap11)
175 writer.WriteAttributeString ("s", dic.Add ("actor"), dic.Add (messageVersion.Envelope.Namespace), Actor);
177 if (messageVersion.Envelope == EnvelopeVersion.Soap12)
178 writer.WriteAttributeString ("s", dic.Add ("role"), dic.Add (messageVersion.Envelope.Namespace), Actor);
181 // mustUnderstand is the same across SOAP 1.1 and 1.2
182 if (MustUnderstand == true)
183 writer.WriteAttributeString ("s", dic.Add ("mustUnderstand"), dic.Add (messageVersion.Envelope.Namespace), "1");
185 // relay is only available on SOAP 1.2
186 if (Relay == true && messageVersion.Envelope == EnvelopeVersion.Soap12)
187 writer.WriteAttributeString ("s", dic.Add ("relay"), dic.Add (messageVersion.Envelope.Namespace), "true");
190 public void WriteHeaderContents (XmlDictionaryWriter writer, MessageVersion messageVersion)
192 this.OnWriteHeaderContents (writer, messageVersion);
195 public void WriteStartHeader (XmlDictionaryWriter writer, MessageVersion messageVersion)
197 this.OnWriteStartHeader (writer, messageVersion);
200 public override string Actor { get { return default_actor; }}
202 public override bool IsReferenceParameter { get { return default_is_ref; }}
204 public override bool MustUnderstand { get { return default_must_understand; }}
206 public override bool Relay { get { return default_relay; }}
208 internal class XmlMessageHeader : MessageHeader
210 bool is_ref, must_understand, relay;
215 // This is required to completely clone body xml that
216 // does not introduce additional xmlns declarations that
217 // blocks canonicalized copy of the input XML.
221 string namespace_uri;
223 public XmlMessageHeader (XmlReader reader, MessageVersion version)
225 var soapNS = version.Envelope.Namespace;
226 var addrNS = version.Addressing.Namespace;
227 Prefix = reader.Prefix;
228 Id = reader.GetAttribute ("Id", Constants.WsuNamespace);
230 string s = reader.GetAttribute ("relay", soapNS);
231 relay = s != null ? XmlConvert.ToBoolean (s) : false;
232 s = reader.GetAttribute ("mustUnderstand", soapNS);
233 must_understand = s != null ? XmlConvert.ToBoolean (s) : false;
234 actor = reader.GetAttribute ("actor", soapNS) ?? String.Empty;
236 s = reader.GetAttribute ("IsReferenceParameter", addrNS);
237 is_ref = s != null ? XmlConvert.ToBoolean (s) : false;
239 local_name = reader.LocalName;
240 namespace_uri = reader.NamespaceURI;
242 body = reader.ReadOuterXml ();
244 body = new XmlDocument ();
245 var w = body.CreateNavigator ().AppendChild ();
246 w.WriteNode (reader, false);
251 public XmlReader CreateReader ()
254 var reader = XmlReader.Create (new StringReader (body));
256 var reader = new XmlNodeReader (body);
258 reader.MoveToContent ();
262 protected override void OnWriteHeaderContents (
263 XmlDictionaryWriter writer, MessageVersion version)
265 var r = CreateReader ();
267 if (r.IsEmptyElement)
268 return; // write nothing
269 for (r.Read (); r.NodeType != XmlNodeType.EndElement;)
270 writer.WriteNode (r, false);
273 public override string Actor { get { return actor; }}
275 public override bool IsReferenceParameter { get { return is_ref; }}
277 public override bool MustUnderstand { get { return must_understand; }}
279 public override string Name { get { return local_name; }}
281 public override string Namespace { get { return namespace_uri; }}
283 public override bool Relay { get { return relay; }}
286 internal class DefaultMessageHeader : MessageHeader
288 string actor, name, ns;
290 XmlObjectSerializer formatter;
291 bool is_ref, must_understand, relay;
293 internal DefaultMessageHeader (string name, string ns, object value, XmlObjectSerializer formatter,
294 bool isReferenceParameter,
295 bool mustUnderstand, string actor, bool relay)
300 this.formatter = formatter;
301 this.is_ref = isReferenceParameter;
302 this.must_understand = mustUnderstand;
303 this.actor = actor ?? String.Empty;
307 protected override void OnWriteHeaderContents (XmlDictionaryWriter writer,
308 MessageVersion version)
310 // FIXME: it's a nasty workaround just to avoid UniqueId output as a string, for bug #577139.
311 if (Value is UniqueId)
312 writer.WriteValue ((UniqueId) Value);
314 this.formatter.WriteObjectContent (writer, value);
317 public object Value { get { return value; } }
319 public override string Actor { get { return actor; }}
321 public override bool IsReferenceParameter { get { return is_ref; }}
323 public override bool MustUnderstand { get { return must_understand; }}
325 public override string Name { get { return name; }}
327 public override string Namespace { get { return ns; }}
329 public override bool Relay { get { return relay; }}