In System.ServiceModel.Description:
[mono-project.git] / mcs / class / System.ServiceModel / System.ServiceModel.Channels / MessageHeaders.cs
blobcd00eff07f15fdc0dc58ca82755bf9562691c206
1 //
2 // System.ServiceModel.MessageHeader.cs
3 //
4 // Author: Duncan Mak (duncan@novell.com)
5 //
6 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining
9 // a copy of this software and associated documentation files (the
10 // "Software"), to deal in the Software without restriction, including
11 // without limitation the rights to use, copy, modify, merge, publish,
12 // distribute, sublicense, and/or sell copies of the Software, and to
13 // permit persons to whom the Software is furnished to do so, subject to
14 // the following conditions:
15 //
16 // The above copyright notice and this permission notice shall be
17 // included in all copies or substantial portions of the Software.
18 //
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 using System;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.IO;
32 using System.Runtime.Serialization;
33 using System.ServiceModel;
34 using System.Xml;
36 namespace System.ServiceModel.Channels
38 public sealed class MessageHeaders : IEnumerable<MessageHeaderInfo>, IEnumerable
40 static string [] empty_strings = new string [0];
42 static readonly XmlReaderSettings reader_settings;
44 static MessageHeaders ()
46 reader_settings = new XmlReaderSettings ();
47 reader_settings.ConformanceLevel = ConformanceLevel.Fragment;
50 List<MessageHeaderInfo> l;
51 Dictionary<Type, XmlObjectSerializer> serializers =
52 new Dictionary<Type, XmlObjectSerializer> ();
53 MessageVersion version;
55 public MessageHeaders (MessageHeaders headers)
56 : this (headers.MessageVersion)
58 CopyHeadersFrom (headers);
61 public MessageHeaders (MessageVersion version)
62 : this (version, 10) // let's say 10 is the initial size
66 public MessageHeaders (MessageVersion version, int capacity)
68 this.version = version;
69 l = new List<MessageHeaderInfo> (capacity);
72 public void Add (MessageHeader header)
74 l.Add (header);
77 public void CopyHeaderFrom (Message m, int index)
79 CopyHeaderFrom (m.Headers, index);
82 public void Clear ()
84 l.Clear ();
87 public void CopyHeaderFrom (MessageHeaders headers, int index)
89 l.Add (headers [index]);
92 public void CopyHeadersFrom (Message m)
94 CopyHeadersFrom (m.Headers);
97 public void CopyHeadersFrom (MessageHeaders headers)
99 foreach (MessageHeaderInfo h in headers)
100 l.Add (h);
103 public void CopyTo (MessageHeaderInfo [] dst, int index)
105 l.CopyTo (dst, index);
108 public int FindHeader (string name, string ns)
110 return FindHeader (name, ns, null);
113 bool HasActor (string actor, string [] candidates)
115 foreach (string c in candidates)
116 if (c == actor)
117 return true;
118 return false;
121 public int FindHeader (string name, string ns, params string [] actors)
123 int found = 0;
124 int retval = -1;
126 for (int i = 0; i < l.Count; i++) {
127 MessageHeaderInfo info = l [i];
129 if (info.Name == name && info.Namespace == ns) {
130 if (found > 1)
131 throw new ArgumentException ("Found multiple matching headers.");
132 // When no actors are passed, it never
133 // matches such header that has an
134 // Actor.
135 if (actors == null && info.Actor == String.Empty ||
136 actors != null && HasActor (info.Actor, actors)) {
137 retval = i;
138 found++;
143 return retval;
146 public IEnumerator<MessageHeaderInfo> GetEnumerator ()
148 return l.GetEnumerator ();
151 XmlObjectSerializer GetSerializer<T> (int headerIndex)
153 if (!serializers.ContainsKey (typeof (T)))
154 serializers [typeof (T)] = new DataContractSerializer (typeof (T), this [headerIndex].Name, this [headerIndex].Namespace);
155 return serializers [typeof (T)];
158 public T GetHeader<T> (int index)
160 if (l.Count <= index)
161 throw new ArgumentOutOfRangeException ("index");
162 var dmh = l [index] as MessageHeader.DefaultMessageHeader;
163 if (dmh != null && dmh.Value != null && typeof (T).IsAssignableFrom (dmh.Value.GetType ()))
164 return (T) dmh.Value;
165 if (typeof (T) == typeof (EndpointAddress)) {
166 XmlDictionaryReader r = GetReaderAtHeader (index);
167 return r.NodeType != XmlNodeType.Element ? default (T) : (T) (object) EndpointAddress.ReadFrom (r);
169 else
170 return GetHeader<T> (index, GetSerializer<T> (index));
173 public T GetHeader<T> (int index, XmlObjectSerializer serializer)
175 if (serializer == null)
176 throw new ArgumentNullException ("serializer");
177 XmlDictionaryReader r = GetReaderAtHeader (index);
178 return (T) serializer.ReadObject (r, false);
181 public T GetHeader<T> (string name, string ns)
183 return GetHeader<T> (name, ns, empty_strings);
186 public T GetHeader<T> (string name, string ns, params string [] actors)
188 int idx = FindHeader (name, ns, actors);
190 if (idx == -1)
191 throw new MessageHeaderException (String.Format ("Header '{0}:{1}' was not found for the argument actors: {2}", ns, name, String.Join (",", actors)));
193 return GetHeader<T> (idx);
196 public T GetHeader<T> (string name, string ns, XmlObjectSerializer serializer)
198 if (serializer == null)
199 throw new ArgumentNullException ("serializer");
200 int idx = FindHeader (name, ns);
202 if (idx < 0)
203 throw new MessageHeaderException (String.Format ("Header '{0}:{1}' was not found", ns, name));
205 return GetHeader<T> (idx, serializer);
208 public XmlDictionaryReader GetReaderAtHeader (int index)
210 if (index >= l.Count)
211 throw new ArgumentOutOfRangeException (String.Format ("Index is out of range. Current header count is {0}", index));
212 MessageHeader item = (MessageHeader) l [index];
214 XmlReader reader =
215 item is MessageHeader.RawMessageHeader ?
216 ((MessageHeader.RawMessageHeader) item).CreateReader () :
217 XmlReader.Create (
218 new StringReader (item.ToString ()),
219 reader_settings);
220 reader.MoveToContent ();
221 XmlDictionaryReader dr = XmlDictionaryReader.CreateDictionaryReader (reader);
222 dr.MoveToContent ();
223 return dr;
226 public bool HaveMandatoryHeadersBeenUnderstood ()
228 throw new NotImplementedException ();
231 public bool HaveMandatoryHeadersBeenUnderstood (params string [] actors)
233 throw new NotImplementedException ();
236 public void Insert (int index, MessageHeader header)
238 l.Insert (index, header);
241 public void RemoveAll (string name, string ns)
243 // Shuffle all the ones we want to keep to the start of the list
244 int j = 0;
245 for (int i = 0; i < l.Count; i++) {
246 if (l[i].Name != name || l[i].Namespace != ns) {
247 l [j++] = l[i];
250 // Trim the extra elements off the end of the list.
251 int count = l.Count - j;
252 for (int i = 0; i < count; i++)
253 l.RemoveAt (l.Count - 1);
256 public void RemoveAt (int index)
258 l.RemoveAt (index);
261 IEnumerator IEnumerable.GetEnumerator ()
263 return ((IEnumerable) l).GetEnumerator ();
266 public void WriteHeader (int index, XmlDictionaryWriter writer)
268 if (version.Envelope == EnvelopeVersion.None)
269 return;
271 // For AddressingVersion.None, don't output the item.
273 // FIXME: It should even ignore Action, but for now
274 // service dispatcher won't work without it.
275 if (version.Addressing == AddressingVersion.None &&
276 l [index].Name != "Action")
277 return;
279 WriteStartHeader (index, writer);
280 WriteHeaderContents (index, writer);
281 writer.WriteEndElement ();
284 public void WriteHeader (int index, XmlWriter writer)
286 WriteHeader (index, XmlDictionaryWriter.CreateDictionaryWriter (writer));
289 public void WriteHeaderContents (int index, XmlDictionaryWriter writer)
291 if (index > l.Count)
292 throw new ArgumentOutOfRangeException ("There is no header at position " + index + ".");
294 MessageHeader h = l [index] as MessageHeader;
296 h.WriteHeaderContents (writer, version);
299 public void WriteHeaderContents (int index, XmlWriter writer)
301 WriteHeaderContents (index, XmlDictionaryWriter.CreateDictionaryWriter (writer));
304 public void WriteStartHeader (int index, XmlDictionaryWriter writer)
306 if (index > l.Count)
307 throw new ArgumentOutOfRangeException ("There is no header at position " + index + ".");
309 MessageHeader h = l [index] as MessageHeader;
311 h.WriteStartHeader (writer, version);
314 public void WriteStartHeader (int index, XmlWriter writer)
316 WriteStartHeader (index, XmlDictionaryWriter.CreateDictionaryWriter (writer));
319 public string Action {
320 get {
321 int idx = FindHeader ("Action", version.Addressing.Namespace);
322 return idx < 0 ? null : GetHeader<string> (idx);
324 set {
325 RemoveAll ("Action", version.Addressing.Namespace);
326 if (value != null)
327 Add (MessageHeader.CreateHeader ("Action", version.Addressing.Namespace, value, true));
331 public int Count {
332 get { return l.Count; }
335 #if !NET_2_1
336 public EndpointAddress FaultTo {
337 get {
338 int idx = FindHeader ("FaultTo", Constants.WSA1);
339 return idx < 0 ? null : GetHeader<EndpointAddress> (idx);
341 set {
342 if (version.Addressing == AddressingVersion.None)
343 throw new InvalidOperationException ("WS-Addressing header is not allowed for AddressingVersion.None");
345 RemoveAll ("FaultTo", Constants.WSA1);
346 if (value != null)
347 Add (MessageHeader.CreateHeader ("FaultTo", Constants.WSA1, EndpointAddress10.FromEndpointAddress (value)));
351 public EndpointAddress From {
352 get {
353 int idx = FindHeader ("From", version.Addressing.Namespace);
354 return idx < 0 ? null : GetHeader<EndpointAddress> (idx);
356 set {
357 if (version.Addressing == AddressingVersion.None)
358 throw new InvalidOperationException ("WS-Addressing header is not allowed for AddressingVersion.None");
360 RemoveAll ("From", Constants.WSA1);
361 if (value != null)
362 Add (MessageHeader.CreateHeader ("From", Constants.WSA1, EndpointAddress10.FromEndpointAddress (value)));
365 #endif
367 public MessageHeaderInfo this [int index] {
368 get { return l [index]; }
371 public UniqueId MessageId {
372 get {
373 int idx = FindHeader ("MessageID", Constants.WSA1);
374 return idx < 0 ? null : new UniqueId (GetHeader<string> (idx));
376 set {
377 if (version.Addressing == AddressingVersion.None)
378 throw new InvalidOperationException ("WS-Addressing header is not allowed for AddressingVersion.None");
380 RemoveAll ("MessageID", Constants.WSA1);
381 if (value != null)
382 Add (MessageHeader.CreateHeader ("MessageID", Constants.WSA1, value.ToString ()));
386 public MessageVersion MessageVersion { get { return version; } }
388 public UniqueId RelatesTo {
389 get {
390 int idx = FindHeader ("RelatesTo", Constants.WSA1);
391 return idx < 0 ? null : new UniqueId (GetHeader<string> (idx));
393 set {
394 if (version.Addressing == AddressingVersion.None)
395 throw new InvalidOperationException ("WS-Addressing header is not allowed for AddressingVersion.None");
397 RemoveAll ("MessageID", Constants.WSA1);
398 if (value != null)
399 Add (MessageHeader.CreateHeader ("RelatesTo", Constants.WSA1, value.ToString ()));
404 #if !NET_2_1
405 public EndpointAddress ReplyTo {
406 get {
407 int idx = FindHeader ("ReplyTo", Constants.WSA1);
408 return idx < 0 ? null : GetHeader<EndpointAddress> (idx);
410 set {
411 if (version.Addressing == AddressingVersion.None)
412 throw new InvalidOperationException ("WS-Addressing header is not allowed for AddressingVersion.None");
414 RemoveAll ("ReplyTo", Constants.WSA1);
415 if (value != null)
416 Add (MessageHeader.CreateHeader ("ReplyTo", Constants.WSA1, EndpointAddress10.FromEndpointAddress (value)));
419 #endif
421 public Uri To {
422 get {
423 int idx = FindHeader ("To", version.Addressing.Namespace);
424 //FIXME: return idx < 0 ? null : GetHeader<Uri> (idx);
425 return idx < 0 ? null : new Uri (GetHeader<string> (idx));
427 set {
428 RemoveAll ("To", version.Addressing.Namespace);
429 if (value != null)
430 Add (MessageHeader.CreateHeader ("To", version.Addressing.Namespace, value.AbsoluteUri, true));
434 [MonoTODO]
435 public UnderstoodHeaders UnderstoodHeaders {
436 get { throw new NotImplementedException (); }