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