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