043b2ab7af08df3875689382a09e41e1210750f3
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel / ClientRuntimeChannel.cs
1 //
2 // ClientRuntimeChannel.cs
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2006 Novell, Inc.  http://www.novell.com
8 //
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:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
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.
27 //
28 using System;
29 using System.Collections.Generic;
30 using System.Reflection;
31 using System.Runtime.Serialization;
32 using System.ServiceModel.Channels;
33 using System.ServiceModel.Description;
34 using System.ServiceModel.Dispatcher;
35 using System.ServiceModel.Security;
36 using System.Threading;
37 using System.Xml;
38
39 namespace System.ServiceModel.MonoInternal
40 {
41 #if DISABLE_REAL_PROXY
42         // FIXME: This is a quick workaround for bug #571907
43         public
44 #endif
45         interface IInternalContextChannel
46         {
47                 ContractDescription Contract { get; }
48
49                 object Process (MethodBase method, string operationName, object [] parameters, OperationContext context);
50
51                 IAsyncResult BeginProcess (MethodBase method, string operationName, object [] parameters, AsyncCallback callback, object asyncState);
52
53                 object EndProcess (MethodBase method, string operationName, object [] parameters, IAsyncResult result);
54         }
55
56 #if DISABLE_REAL_PROXY
57         // FIXME: This is a quick workaround for bug #571907
58         public
59 #endif
60         class ClientRuntimeChannel
61                 : CommunicationObject, IClientChannel, IInternalContextChannel
62         {
63                 ClientRuntime runtime;
64                 EndpointAddress remote_address;
65                 ContractDescription contract;
66                 MessageVersion message_version;
67                 TimeSpan default_open_timeout, default_close_timeout;
68                 IChannel channel;
69                 IChannelFactory factory;
70
71                 #region delegates
72                 readonly ProcessDelegate _processDelegate;
73
74                 delegate object ProcessDelegate (MethodBase method, string operationName, bool isAsync, ref object [] parameters, OperationContext context);
75
76                 readonly RequestDelegate requestDelegate;
77
78                 delegate Message RequestDelegate (Message msg, TimeSpan timeout);
79
80                 readonly SendDelegate sendDelegate;
81
82                 delegate void SendDelegate (Message msg, TimeSpan timeout);
83                 #endregion
84
85                 public ClientRuntimeChannel (ServiceEndpoint endpoint,
86                         ChannelFactory channelFactory, EndpointAddress remoteAddress, Uri via)
87                         : this (endpoint.CreateClientRuntime (null), endpoint.Contract, channelFactory.DefaultOpenTimeout, channelFactory.DefaultCloseTimeout, null, channelFactory.OpenedChannelFactory, endpoint.Binding.MessageVersion, remoteAddress, via)
88                 {
89                 }
90
91                 public ClientRuntimeChannel (ClientRuntime runtime, ContractDescription contract, TimeSpan openTimeout, TimeSpan closeTimeout, IChannel contextChannel, IChannelFactory factory, MessageVersion messageVersion, EndpointAddress remoteAddress, Uri via)
92                 {
93                         if (runtime == null)
94                                 throw new ArgumentNullException ("runtime");
95                         if (messageVersion == null)
96                                 throw new ArgumentNullException ("messageVersion");
97                         this.runtime = runtime;
98                         this.remote_address = remoteAddress;
99                         if (runtime.Via == null)
100                                 runtime.Via = via ?? (remote_address != null ?remote_address.Uri : null);
101                         this.contract = contract;
102                         this.message_version = messageVersion;
103                         default_open_timeout = openTimeout;
104                         default_close_timeout = closeTimeout;
105                         _processDelegate = new ProcessDelegate (Process);
106                         requestDelegate = new RequestDelegate (Request);
107                         sendDelegate = new SendDelegate (Send);
108
109                         // default values
110                         AllowInitializationUI = true;
111                         OperationTimeout = TimeSpan.FromMinutes (1);
112
113                         if (contextChannel != null)
114                                 channel = contextChannel;
115                         else {
116                                 var method = factory.GetType ().GetMethod ("CreateChannel", new Type [] {typeof (EndpointAddress), typeof (Uri)});
117                                 try {
118                                         channel = (IChannel) method.Invoke (factory, new object [] {remote_address, Via});
119                                         this.factory = factory;
120                                 } catch (TargetInvocationException ex) {
121                                         if (ex.InnerException != null)
122                                                 throw ex.InnerException;
123                                         else
124                                                 throw;
125                                 }
126                         }
127                 }
128
129                 public ContractDescription Contract {
130                         get { return contract; }
131                 }
132
133                 public ClientRuntime Runtime {
134                         get { return runtime; }
135                 }
136
137                 IRequestChannel RequestChannel {
138                         get { return channel as IRequestChannel; }
139                 }
140
141                 IOutputChannel OutputChannel {
142                         get { return channel as IOutputChannel; }
143                 }
144
145                 internal IDuplexChannel DuplexChannel {
146                         get { return channel as IDuplexChannel; }
147                 }
148
149                 #region IClientChannel
150
151                 bool did_interactive_initialization;
152
153                 public bool AllowInitializationUI { get; set; }
154
155                 public bool DidInteractiveInitialization {
156                         get { return did_interactive_initialization; }
157                 }
158
159                 public Uri Via {
160                         get { return runtime.Via; }
161                 }
162
163                 class DelegatingWaitHandle : WaitHandle
164                 {
165                         public DelegatingWaitHandle (IAsyncResult [] results)
166                         {
167                                 this.results = results;
168                         }
169
170                         IAsyncResult [] results;
171
172                         protected override void Dispose (bool disposing)
173                         {
174                                 if (disposing)
175                                         foreach (var r in results)
176                                                 r.AsyncWaitHandle.Close ();
177                         }
178
179                         public override bool WaitOne ()
180                         {
181                                 foreach (var r in results)
182                                         r.AsyncWaitHandle.WaitOne ();
183                                 return true;
184                         }
185
186                         public override bool WaitOne (int millisecondsTimeout)
187                         {
188                                 return WaitHandle.WaitAll (ResultWaitHandles, millisecondsTimeout);
189                         }
190
191                         WaitHandle [] ResultWaitHandles {
192                                 get {
193                                         var arr = new WaitHandle [results.Length];
194                                         for (int i = 0; i < arr.Length; i++)
195                                                 arr [i] = results [i].AsyncWaitHandle;
196                                         return arr;
197                                 }
198                         }
199
200                         public override bool WaitOne (int millisecondsTimeout, bool exitContext)
201                         {
202                                 return WaitHandle.WaitAll (ResultWaitHandles, millisecondsTimeout, exitContext);
203                         }
204
205                         public override bool WaitOne (TimeSpan timeout, bool exitContext)
206                         {
207                                 return WaitHandle.WaitAll (ResultWaitHandles, timeout, exitContext);
208                         }
209                 }
210
211                 class DisplayUIAsyncResult : IAsyncResult
212                 {
213                         public DisplayUIAsyncResult (IAsyncResult [] results)
214                         {
215                                 this.results = results;
216                         }
217
218                         IAsyncResult [] results;
219
220                         internal IAsyncResult [] Results {
221                                 get { return results; }
222                         }
223
224                         public object AsyncState {
225                                 get { return null; }
226                         }
227
228                         WaitHandle wait_handle;
229
230                         public WaitHandle AsyncWaitHandle {
231                                 get {
232                                         if (wait_handle == null)
233                                                 wait_handle = new DelegatingWaitHandle (results);
234                                         return wait_handle;
235                                 }
236                         }
237
238                         public bool CompletedSynchronously {
239                                 get {
240                                         foreach (var r in results)
241                                                 if (!r.CompletedSynchronously)
242                                                         return false;
243                                         return true;
244                                 }
245                         }
246                         public bool IsCompleted {
247                                 get {
248                                         foreach (var r in results)
249                                                 if (!r.IsCompleted)
250                                                         return false;
251                                         return true;
252                                 }
253                         }
254                 }
255
256                 public IAsyncResult BeginDisplayInitializationUI (
257                         AsyncCallback callback, object state)
258                 {
259                         OnInitializationUI ();
260                         IAsyncResult [] arr = new IAsyncResult [runtime.InteractiveChannelInitializers.Count];
261                         int i = 0;
262                         foreach (var init in runtime.InteractiveChannelInitializers)
263                                 arr [i++] = init.BeginDisplayInitializationUI (this, callback, state);
264                         return new DisplayUIAsyncResult (arr);
265                 }
266
267                 public void EndDisplayInitializationUI (
268                         IAsyncResult result)
269                 {
270                         DisplayUIAsyncResult r = (DisplayUIAsyncResult) result;
271                         int i = 0;
272                         foreach (var init in runtime.InteractiveChannelInitializers)
273                                 init.EndDisplayInitializationUI (r.Results [i++]);
274
275                         did_interactive_initialization = true;
276                 }
277
278                 public void DisplayInitializationUI ()
279                 {
280                         OnInitializationUI ();
281                         foreach (var init in runtime.InteractiveChannelInitializers)
282                                 init.EndDisplayInitializationUI (init.BeginDisplayInitializationUI (this, null, null));
283
284                         did_interactive_initialization = true;
285                 }
286
287                 void OnInitializationUI ()
288                 {
289                         if (!AllowInitializationUI && runtime.InteractiveChannelInitializers.Count > 0)
290                                 throw new InvalidOperationException ("AllowInitializationUI is set to false but the client runtime contains one or more InteractiveChannelInitializers.");
291                 }
292
293                 public void Dispose ()
294                 {
295                         Close ();
296                 }
297
298                 public event EventHandler<UnknownMessageReceivedEventArgs> UnknownMessageReceived;
299
300                 #endregion
301
302                 #region IContextChannel
303
304                 [MonoTODO]
305                 public bool AllowOutputBatching { get; set; }
306
307                 public IInputSession InputSession {
308                         get {
309                                 ISessionChannel<IInputSession> ch = RequestChannel as ISessionChannel<IInputSession>;
310                                 ch = ch ?? OutputChannel as ISessionChannel<IInputSession>;
311                                 if (ch != null)
312                                         return ch.Session;
313                                 var dch = OutputChannel as ISessionChannel<IDuplexSession>;
314                                 return dch != null ? dch.Session : null;
315                         }
316                 }
317
318                 public EndpointAddress LocalAddress {
319                         get {
320                                 var dc = OperationChannel as IDuplexChannel;
321                                 return dc != null ? dc.LocalAddress : null;
322                         }
323                 }
324
325                 [MonoTODO]
326                 public TimeSpan OperationTimeout { get; set; }
327
328                 public IOutputSession OutputSession {
329                         get {
330                                 ISessionChannel<IOutputSession> ch = RequestChannel as ISessionChannel<IOutputSession>;
331                                 ch = ch ?? OutputChannel as ISessionChannel<IOutputSession>;
332                                 if (ch != null)
333                                         return ch.Session;
334                                 var dch = OutputChannel as ISessionChannel<IDuplexSession>;
335                                 return dch != null ? dch.Session : null;
336                         }
337                 }
338
339                 public EndpointAddress RemoteAddress {
340                         get { return RequestChannel != null ? RequestChannel.RemoteAddress : OutputChannel.RemoteAddress; }
341                 }
342
343                 public string SessionId {
344                         get { return OutputSession != null ? OutputSession.Id : InputSession != null ? InputSession.Id : null; }
345                 }
346
347                 #endregion
348
349                 // CommunicationObject
350                 protected internal override TimeSpan DefaultOpenTimeout {
351                         get { return default_open_timeout; }
352                 }
353
354                 protected internal override TimeSpan DefaultCloseTimeout {
355                         get { return default_close_timeout; }
356                 }
357
358                 protected override void OnAbort ()
359                 {
360                         channel.Abort ();
361                         if (factory != null) // ... is it valid?
362                                 factory.Abort ();
363                 }
364
365                 Action<TimeSpan> close_delegate;
366
367                 protected override IAsyncResult OnBeginClose (
368                         TimeSpan timeout, AsyncCallback callback, object state)
369                 {
370                         if (close_delegate == null)
371                                 close_delegate = new Action<TimeSpan> (OnClose);
372                         return close_delegate.BeginInvoke (timeout, callback, state);
373                 }
374
375                 protected override void OnEndClose (IAsyncResult result)
376                 {
377                         close_delegate.EndInvoke (result);
378                 }
379
380                 protected override void OnClose (TimeSpan timeout)
381                 {
382                         DateTime start = DateTime.Now;
383                         if (channel.State == CommunicationState.Opened)
384                                 channel.Close (timeout);
385                 }
386
387                 Action<TimeSpan> open_callback;
388
389                 protected override IAsyncResult OnBeginOpen (
390                         TimeSpan timeout, AsyncCallback callback, object state)
391                 {
392                         if (open_callback == null)
393                                 open_callback = new Action<TimeSpan> (OnOpen);
394                         return open_callback.BeginInvoke (timeout, callback, state);
395                 }
396
397                 protected override void OnEndOpen (IAsyncResult result)
398                 {
399                         if (open_callback == null)
400                                 throw new InvalidOperationException ("Async open operation has not started");
401                         open_callback.EndInvoke (result);
402                 }
403
404                 protected override void OnOpen (TimeSpan timeout)
405                 {
406                         if (runtime.InteractiveChannelInitializers.Count > 0 && !DidInteractiveInitialization)
407                                 throw new InvalidOperationException ("The client runtime is assigned interactive channel initializers, and in such case DisplayInitializationUI must be called before the channel is opened.");
408                         if (channel.State == CommunicationState.Created)
409                                 channel.Open (timeout);
410                 }
411
412                 // IChannel
413
414                 IChannel OperationChannel {
415                         get { return channel; }
416                 }
417
418                 public T GetProperty<T> () where T : class
419                 {
420                         if (typeof (T) == typeof (MessageVersion))
421                                 return (T) (object) message_version;
422                         return OperationChannel.GetProperty<T> ();
423                 }
424
425                 // IExtensibleObject<IContextChannel>
426
427                 IExtensionCollection<IContextChannel> extensions;
428
429                 public IExtensionCollection<IContextChannel> Extensions {
430                         get {
431                                 if (extensions == null)
432                                         extensions = new ExtensionCollection<IContextChannel> (this);
433                                 return extensions;
434                         }
435                 }
436
437                 #region Request/Output processing
438
439                 public IAsyncResult BeginProcess (MethodBase method, string operationName, object [] parameters, AsyncCallback callback, object asyncState)
440                 {
441                         var p = parameters;
442                         var retval = _processDelegate.BeginInvoke (method, operationName, true, ref p, OperationContext.Current, callback, asyncState);
443                         if (p != parameters)
444                                 throw new InvalidOperationException ();
445                         return retval;
446                 }
447
448                 public object EndProcess (MethodBase method, string operationName, object [] parameters, IAsyncResult result)
449                 {
450                         if (result == null)
451                                 throw new ArgumentNullException ("result");
452                         if (parameters == null)
453                                 throw new ArgumentNullException ("parameters");
454
455                         object[] p = parameters;
456                         var retval = _processDelegate.EndInvoke (ref p, result);
457                         if (p == parameters)
458                                 return retval;
459
460                         if (p.Length != parameters.Length)
461                                 throw new InvalidOperationException ();
462                         Array.Copy (p, parameters, p.Length);
463                         return retval;
464                 }
465
466                 public object Process (MethodBase method, string operationName, object [] parameters, OperationContext context)
467                 {
468                         var p = parameters;
469                         var retval = Process (method, operationName, false, ref p, context);
470                         if (p != parameters)
471                                 throw new InvalidOperationException ();
472                         return retval;
473                 }
474
475                 object Process (MethodBase method, string operationName, bool isAsync, ref object [] parameters, OperationContext context)
476                 {
477                         var previousContext = OperationContext.Current;
478                         try {
479                                 // Inherit the context from the calling thread
480                                 OperationContext.Current = context;
481
482                                 return DoProcess (method, operationName, isAsync, ref parameters, context);
483                         } catch (Exception ex) {
484                                 throw;
485                         } finally {
486                                 // Reset the context before the thread goes back into the pool
487                                 OperationContext.Current = previousContext;
488                         }
489                 }
490
491                 object DoProcess (MethodBase method, string operationName, bool isAsync, ref object [] parameters, OperationContext context)
492                 {
493                         if (AllowInitializationUI)
494                                 DisplayInitializationUI ();
495                         OperationDescription od = SelectOperation (method, operationName, parameters);
496
497                         if (State != CommunicationState.Opened)
498                                 Open ();
499
500                         if (!od.IsOneWay)
501                                 return Request (od, isAsync, ref parameters, context);
502                         else {
503                                 Output (od, parameters, context);
504                                 return null;
505                         }
506                 }
507
508                 OperationDescription SelectOperation (MethodBase method, string operationName, object [] parameters)
509                 {
510                         string operation;
511                         if (Runtime.OperationSelector != null)
512                                 operation = Runtime.OperationSelector.SelectOperation (method, parameters);
513                         else
514                                 operation = operationName;
515                         OperationDescription od = contract.Operations.Find (operation);
516                         if (od == null)
517                                 throw new Exception (String.Format ("OperationDescription for operation '{0}' was not found in its internally-generated contract.", operation));
518                         return od;
519                 }
520
521                 void Output (OperationDescription od, object [] parameters, OperationContext context)
522                 {
523                         ClientOperation op = runtime.Operations [od.Name];
524                         Send (CreateRequest (op, parameters, context), OperationTimeout);
525                 }
526
527                 object Request (OperationDescription od, bool isAsync, ref object [] parameters, OperationContext context)
528                 {
529                         ClientOperation op = runtime.Operations [od.Name];
530                         object [] inspections = new object [runtime.MessageInspectors.Count];
531                         Message req = CreateRequest (op, parameters, context);
532
533                         for (int i = 0; i < inspections.Length; i++)
534                                 inspections [i] = runtime.MessageInspectors [i].BeforeSendRequest (ref req, this);
535
536                         Message res = Request (req, OperationTimeout);
537                         if (res.IsFault) {
538                                 var resb = res.CreateBufferedCopy (runtime.MaxFaultSize);
539                                 MessageFault fault = MessageFault.CreateFault (resb.CreateMessage (), runtime.MaxFaultSize);
540                                 var conv = OperationChannel.GetProperty<FaultConverter> () ?? FaultConverter.GetDefaultFaultConverter (res.Version);
541                                 Exception ex;
542                                 if (!conv.TryCreateException (resb.CreateMessage (), fault, out ex)) {
543                                         if (fault.HasDetail) {
544                                                 Type detailType = typeof (ExceptionDetail);
545                                                 var freader = fault.GetReaderAtDetailContents ();
546                                                 DataContractSerializer ds = null;
547                                                 foreach (var fci in op.FaultContractInfos)
548                                                         if (res.Headers.Action == fci.Action || fci.Serializer.IsStartObject (freader)) {
549                                                                 detailType = fci.Detail;
550                                                                 ds = fci.Serializer;
551                                                                 break;
552                                                         }
553                                                 if (ds == null)
554                                                         ds = new DataContractSerializer (detailType);
555                                                 var detail = ds.ReadObject (freader);
556                                                 ex = (Exception) Activator.CreateInstance (typeof (FaultException<>).MakeGenericType (detailType), new object [] {detail, fault.Reason, fault.Code, res.Headers.Action});
557                                         }
558
559                                         if (ex == null)
560                                                 ex = new FaultException (fault);
561                                 }
562                                 throw ex;
563                         }
564
565                         for (int i = 0; i < inspections.Length; i++)
566                                 runtime.MessageInspectors [i].AfterReceiveReply (ref res, inspections [i]);
567
568                         if (!op.DeserializeReply)
569                                 return res;
570
571                         if (isAsync && od.EndMethod != null) {
572                                 var endParams = od.EndMethod.GetParameters ();
573                                 parameters = new object [endParams.Length - 1];
574                         }
575
576                         return op.Formatter.DeserializeReply (res, parameters);
577                 }
578
579                 #region Message-based Request() and Send()
580                 // They are internal for ClientBase<T>.ChannelBase use.
581                 internal Message Request (Message msg, TimeSpan timeout)
582                 {
583                         if (RequestChannel != null)
584                                 return RequestChannel.Request (msg, timeout);
585                         else
586                                 return RequestCorrelated (msg, timeout, OutputChannel);
587                 }
588
589                 internal virtual Message RequestCorrelated (Message msg, TimeSpan timeout, IOutputChannel channel)
590                 {
591                         // FIXME: implement ConcurrencyMode check:
592                         // if it is .Single && this instance for a callback channel && the operation is invoked inside service operation, then error.
593
594                         DateTime startTime = DateTime.Now;
595                         OutputChannel.Send (msg, timeout);
596                         return ((IDuplexChannel) channel).Receive (timeout - (DateTime.Now - startTime));
597                 }
598
599                 internal IAsyncResult BeginRequest (Message msg, TimeSpan timeout, AsyncCallback callback, object state)
600                 {
601                         return requestDelegate.BeginInvoke (msg, timeout, callback, state);
602                 }
603
604                 internal Message EndRequest (IAsyncResult result)
605                 {
606                         return requestDelegate.EndInvoke (result);
607                 }
608
609                 internal void Send (Message msg, TimeSpan timeout)
610                 {
611                         if (OutputChannel != null)
612                                 OutputChannel.Send (msg, timeout);
613                         else
614                                 RequestChannel.Request (msg, timeout); // and ignore returned message.
615                 }
616
617                 internal IAsyncResult BeginSend (Message msg, TimeSpan timeout, AsyncCallback callback, object state)
618                 {
619                         return sendDelegate.BeginInvoke (msg, timeout, callback, state);
620                 }
621
622                 internal void EndSend (IAsyncResult result)
623                 {
624                         sendDelegate.EndInvoke (result);
625                 }
626                 #endregion
627
628                 Message CreateRequest (ClientOperation op, object [] parameters, OperationContext context)
629                 {
630                         MessageVersion version = message_version;
631                         if (version == null)
632                                 version = MessageVersion.Default;
633
634                         Message msg;
635                         if (op.SerializeRequest)
636                                 msg = op.Formatter.SerializeRequest (
637                                         version, parameters);
638                         else {
639                                 if (parameters.Length != 1)
640                                         throw new ArgumentException (String.Format ("Argument parameters does not match the expected input. It should contain only a Message, but has {0} parameters", parameters.Length));
641                                 if (!(parameters [0] is Message))
642                                         throw new ArgumentException (String.Format ("Argument should be only a Message, but has {0}", parameters [0] != null ? parameters [0].GetType ().FullName : "null"));
643                                 msg = (Message) parameters [0];
644                         }
645
646                         context = context ?? OperationContext.Current;
647                         if (context != null) {
648                                 // CopyHeadersFrom does not work here (brings duplicates -> error)
649                                 foreach (var mh in context.OutgoingMessageHeaders) {
650                                         int x = msg.Headers.FindHeader (mh.Name, mh.Namespace, mh.Actor);
651                                         if (x >= 0)
652                                                 msg.Headers.RemoveAt (x);
653                                         msg.Headers.Add ((MessageHeader) mh);
654                                 }
655                                 msg.Properties.CopyProperties (context.OutgoingMessageProperties);
656                         }
657
658                         // FIXME: disabling MessageId as it's not seen for bug #567672 case. But might be required for PeerDuplexChannel. Check it later.
659                         //if (OutputSession != null)
660                         //      msg.Headers.MessageId = new UniqueId (OutputSession.Id);
661                         msg.Properties.AllowOutputBatching = AllowOutputBatching;
662
663                         if (msg.Version.Addressing.Equals (AddressingVersion.WSAddressing10)) {
664                                 if (msg.Headers.MessageId == null)
665                                         msg.Headers.MessageId = new UniqueId ();
666                                 if (msg.Headers.ReplyTo == null)
667                                         msg.Headers.ReplyTo = new EndpointAddress (Constants.WsaAnonymousUri);
668                                 if (msg.Headers.To == null && RemoteAddress != null)
669                                         msg.Headers.To = RemoteAddress.Uri;
670                         }
671
672                         return msg;
673                 }
674
675                 #endregion
676         }
677 }