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 Process(MethodBase method, string operationName, object [] parameters, OperationContext context)49 object Process (MethodBase method, string operationName, object [] parameters, OperationContext context); 50 BeginProcess(MethodBase method, string operationName, object [] parameters, AsyncCallback callback, object asyncState)51 IAsyncResult BeginProcess (MethodBase method, string operationName, object [] parameters, AsyncCallback callback, object asyncState); 52 EndProcess(MethodBase method, string operationName, object [] parameters, IAsyncResult result)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 ProcessDelegate(MethodBase method, string operationName, bool isAsync, ref object [] parameters, OperationContext context)76 delegate object ProcessDelegate (MethodBase method, string operationName, bool isAsync, ref object [] parameters, OperationContext context); 77 78 readonly RequestDelegate requestDelegate; 79 RequestDelegate(Message msg, TimeSpan timeout)80 delegate Message RequestDelegate (Message msg, TimeSpan timeout); 81 82 readonly SendDelegate sendDelegate; 83 SendDelegate(Message msg, TimeSpan timeout)84 delegate void SendDelegate (Message msg, TimeSpan timeout); 85 #endregion 86 ClientRuntimeChannel(ServiceEndpoint endpoint, ChannelFactory channelFactory, EndpointAddress remoteAddress, Uri via)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 ClientRuntimeChannel(ClientRuntime runtime, ContractDescription contract, TimeSpan openTimeout, TimeSpan closeTimeout, IChannel contextChannel, IChannelFactory factory, MessageVersion messageVersion, EndpointAddress remoteAddress, Uri via)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 { DelegatingWaitHandle(IAsyncResult [] results)167 public DelegatingWaitHandle (IAsyncResult [] results) 168 { 169 this.results = results; 170 } 171 172 IAsyncResult [] results; 173 Dispose(bool disposing)174 protected override void Dispose (bool disposing) 175 { 176 if (disposing) 177 foreach (var r in results) 178 r.AsyncWaitHandle.Close (); 179 } 180 WaitOne()181 public override bool WaitOne () 182 { 183 foreach (var r in results) 184 r.AsyncWaitHandle.WaitOne (); 185 return true; 186 } 187 WaitOne(int millisecondsTimeout)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 WaitOne(int millisecondsTimeout, bool exitContext)202 public override bool WaitOne (int millisecondsTimeout, bool exitContext) 203 { 204 return WaitHandle.WaitAll (ResultWaitHandles, millisecondsTimeout, exitContext); 205 } 206 WaitOne(TimeSpan timeout, bool exitContext)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 { DisplayUIAsyncResult(IAsyncResult [] results)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 BeginDisplayInitializationUI( AsyncCallback callback, object state)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 EndDisplayInitializationUI( IAsyncResult result)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 DisplayInitializationUI()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 OnInitializationUI()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 Dispose()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 OnAbort()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 OnBeginClose( TimeSpan timeout, AsyncCallback callback, object state)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 OnEndClose(IAsyncResult result)379 protected override void OnEndClose (IAsyncResult result) 380 { 381 close_delegate.EndInvoke (result); 382 } 383 OnClose(TimeSpan timeout)384 protected override void OnClose (TimeSpan timeout) 385 { 386 if (channel.State == CommunicationState.Opened) 387 channel.Close (timeout); 388 } 389 390 Action<TimeSpan> open_callback; 391 OnBeginOpen( TimeSpan timeout, AsyncCallback callback, object state)392 protected override IAsyncResult OnBeginOpen ( 393 TimeSpan timeout, AsyncCallback callback, object state) 394 { 395 if (open_callback == null) 396 open_callback = new Action<TimeSpan> (OnOpen); 397 return open_callback.BeginInvoke (timeout, callback, state); 398 } 399 OnEndOpen(IAsyncResult result)400 protected override void OnEndOpen (IAsyncResult result) 401 { 402 if (open_callback == null) 403 throw new InvalidOperationException ("Async open operation has not started"); 404 open_callback.EndInvoke (result); 405 } 406 OnOpen(TimeSpan timeout)407 protected override void OnOpen (TimeSpan timeout) 408 { 409 if (runtime.InteractiveChannelInitializers.Count > 0 && !DidInteractiveInitialization) 410 throw new InvalidOperationException ("The client runtime is assigned interactive channel initializers, and in such case DisplayInitializationUI must be called before the channel is opened."); 411 if (channel.State == CommunicationState.Created) 412 channel.Open (timeout); 413 } 414 415 // IChannel 416 417 IChannel OperationChannel { 418 get { return channel; } 419 } 420 421 public T GetProperty<T> () where T : class 422 { 423 if (typeof (T) == typeof (MessageVersion)) 424 return (T) (object) message_version; 425 return OperationChannel.GetProperty<T> (); 426 } 427 428 // IExtensibleObject<IContextChannel> 429 430 IExtensionCollection<IContextChannel> extensions; 431 432 public IExtensionCollection<IContextChannel> Extensions { 433 get { 434 if (extensions == null) 435 extensions = new ExtensionCollection<IContextChannel> (this); 436 return extensions; 437 } 438 } 439 440 #region Request/Output processing 441 BeginProcess(MethodBase method, string operationName, object [] parameters, AsyncCallback callback, object asyncState)442 public IAsyncResult BeginProcess (MethodBase method, string operationName, object [] parameters, AsyncCallback callback, object asyncState) 443 { 444 var p = parameters; 445 var retval = _processDelegate.BeginInvoke (method, operationName, true, ref p, OperationContext.Current, callback, asyncState); 446 if (p != parameters) 447 throw new InvalidOperationException (); 448 return retval; 449 } 450 EndProcess(MethodBase method, string operationName, object [] parameters, IAsyncResult result)451 public object EndProcess (MethodBase method, string operationName, object [] parameters, IAsyncResult result) 452 { 453 if (result == null) 454 throw new ArgumentNullException ("result"); 455 if (parameters == null) 456 throw new ArgumentNullException ("parameters"); 457 458 object[] p = parameters; 459 var retval = _processDelegate.EndInvoke (ref p, result); 460 if (p == parameters) 461 return retval; 462 463 Array.Copy (p, parameters, p.Length); 464 return retval; 465 } 466 Process(MethodBase method, string operationName, object [] parameters, OperationContext context)467 public object Process (MethodBase method, string operationName, object [] parameters, OperationContext context) 468 { 469 var p = parameters; 470 var retval = Process (method, operationName, false, ref p, context); 471 if (p != parameters) 472 throw new InvalidOperationException (); 473 return retval; 474 } 475 Process(MethodBase method, string operationName, bool isAsync, ref object [] parameters, OperationContext context)476 object Process (MethodBase method, string operationName, bool isAsync, ref object [] parameters, OperationContext context) 477 { 478 var previousContext = OperationContext.Current; 479 try { 480 // Inherit the context from the calling thread 481 OperationContext.Current = context; 482 483 return DoProcess (method, operationName, isAsync, ref parameters, context); 484 } catch (Exception ex) { 485 throw; 486 } finally { 487 // Reset the context before the thread goes back into the pool 488 OperationContext.Current = previousContext; 489 } 490 } 491 DoProcess(MethodBase method, string operationName, bool isAsync, ref object [] parameters, OperationContext context)492 object DoProcess (MethodBase method, string operationName, bool isAsync, ref object [] parameters, OperationContext context) 493 { 494 if (AllowInitializationUI) 495 DisplayInitializationUI (); 496 OperationDescription od = SelectOperation (method, operationName, parameters); 497 498 if (State != CommunicationState.Opened) 499 Open (); 500 501 if (!od.IsOneWay) 502 return Request (od, isAsync, ref parameters, context); 503 else { 504 Output (od, parameters, context); 505 return null; 506 } 507 } 508 SelectOperation(MethodBase method, string operationName, object [] parameters)509 OperationDescription SelectOperation (MethodBase method, string operationName, object [] parameters) 510 { 511 string operation; 512 if (Runtime.OperationSelector != null) 513 operation = Runtime.OperationSelector.SelectOperation (method, parameters); 514 else 515 operation = operationName; 516 OperationDescription od = contract.Operations.Find (operation); 517 if (od == null) 518 throw new Exception (String.Format ("OperationDescription for operation '{0}' was not found in its internally-generated contract.", operation)); 519 return od; 520 } 521 Output(OperationDescription od, object [] parameters, OperationContext context)522 void Output (OperationDescription od, object [] parameters, OperationContext context) 523 { 524 ClientOperation op = runtime.Operations [od.Name]; 525 Send (CreateRequest (op, parameters, context), OperationTimeout); 526 } 527 Request(OperationDescription od, bool isAsync, ref object [] parameters, OperationContext context)528 object Request (OperationDescription od, bool isAsync, ref object [] parameters, OperationContext context) 529 { 530 ClientOperation op = runtime.Operations [od.Name]; 531 object [] inspections = new object [runtime.MessageInspectors.Count]; 532 Message req = CreateRequest (op, parameters, context); 533 534 for (int i = 0; i < inspections.Length; i++) 535 inspections [i] = runtime.MessageInspectors [i].BeforeSendRequest (ref req, this); 536 537 Message res = Request (req, OperationTimeout); 538 if (res.IsFault) { 539 var resb = res.CreateBufferedCopy (runtime.MaxFaultSize); 540 MessageFault fault = MessageFault.CreateFault (resb.CreateMessage (), runtime.MaxFaultSize); 541 var conv = OperationChannel.GetProperty<FaultConverter> () ?? FaultConverter.GetDefaultFaultConverter (res.Version); 542 Exception ex; 543 if (!conv.TryCreateException (resb.CreateMessage (), fault, out ex)) { 544 if (fault.HasDetail) { 545 Type detailType = typeof (ExceptionDetail); 546 var freader = fault.GetReaderAtDetailContents (); 547 DataContractSerializer ds = null; 548 foreach (var fci in op.FaultContractInfos) 549 if (res.Headers.Action == fci.Action || fci.Serializer.IsStartObject (freader)) { 550 detailType = fci.Detail; 551 ds = fci.Serializer; 552 break; 553 } 554 if (ds == null) 555 ds = new DataContractSerializer (detailType); 556 var detail = ds.ReadObject (freader); 557 ex = (Exception) Activator.CreateInstance (typeof (FaultException<>).MakeGenericType (detailType), new object [] {detail, fault.Reason, fault.Code, res.Headers.Action}); 558 } 559 560 if (ex == null) 561 ex = new FaultException (fault); 562 } 563 throw ex; 564 } 565 566 for (int i = 0; i < inspections.Length; i++) 567 runtime.MessageInspectors [i].AfterReceiveReply (ref res, inspections [i]); 568 569 if (!op.DeserializeReply) 570 return res; 571 572 if (isAsync && od.EndMethod != null) { 573 var endParams = od.EndMethod.GetParameters (); 574 parameters = new object [endParams.Length - 1]; 575 } 576 577 return op.Formatter.DeserializeReply (res, parameters); 578 } 579 580 #region Message-based Request() and Send() 581 // They are internal for ClientBase<T>.ChannelBase use. Request(Message msg, TimeSpan timeout)582 internal Message Request (Message msg, TimeSpan timeout) 583 { 584 if (RequestChannel != null) 585 return RequestChannel.Request (msg, timeout); 586 else 587 return RequestCorrelated (msg, timeout, OutputChannel); 588 } 589 RequestCorrelated(Message msg, TimeSpan timeout, IOutputChannel channel)590 internal virtual Message RequestCorrelated (Message msg, TimeSpan timeout, IOutputChannel channel) 591 { 592 // FIXME: implement ConcurrencyMode check: 593 // if it is .Single && this instance for a callback channel && the operation is invoked inside service operation, then error. 594 595 DateTime startTime = DateTime.UtcNow; 596 OutputChannel.Send (msg, timeout); 597 return ((IDuplexChannel) channel).Receive (timeout - (DateTime.UtcNow - startTime)); 598 } 599 BeginRequest(Message msg, TimeSpan timeout, AsyncCallback callback, object state)600 internal IAsyncResult BeginRequest (Message msg, TimeSpan timeout, AsyncCallback callback, object state) 601 { 602 return requestDelegate.BeginInvoke (msg, timeout, callback, state); 603 } 604 EndRequest(IAsyncResult result)605 internal Message EndRequest (IAsyncResult result) 606 { 607 return requestDelegate.EndInvoke (result); 608 } 609 Send(Message msg, TimeSpan timeout)610 internal void Send (Message msg, TimeSpan timeout) 611 { 612 if (OutputChannel != null) 613 OutputChannel.Send (msg, timeout); 614 else 615 RequestChannel.Request (msg, timeout); // and ignore returned message. 616 } 617 BeginSend(Message msg, TimeSpan timeout, AsyncCallback callback, object state)618 internal IAsyncResult BeginSend (Message msg, TimeSpan timeout, AsyncCallback callback, object state) 619 { 620 return sendDelegate.BeginInvoke (msg, timeout, callback, state); 621 } 622 EndSend(IAsyncResult result)623 internal void EndSend (IAsyncResult result) 624 { 625 sendDelegate.EndInvoke (result); 626 } 627 #endregion 628 CreateRequest(ClientOperation op, object [] parameters, OperationContext context)629 Message CreateRequest (ClientOperation op, object [] parameters, OperationContext context) 630 { 631 MessageVersion version = message_version; 632 if (version == null) 633 version = MessageVersion.Default; 634 635 Message msg; 636 if (op.SerializeRequest) 637 msg = op.Formatter.SerializeRequest ( 638 version, parameters); 639 else { 640 if (parameters.Length != 1) 641 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)); 642 if (!(parameters [0] is Message)) 643 throw new ArgumentException (String.Format ("Argument should be only a Message, but has {0}", parameters [0] != null ? parameters [0].GetType ().FullName : "null")); 644 msg = (Message) parameters [0]; 645 } 646 647 context = context ?? OperationContext.Current; 648 if (context != null) { 649 // CopyHeadersFrom does not work here (brings duplicates -> error) 650 foreach (var mh in context.OutgoingMessageHeaders) { 651 int x = msg.Headers.FindHeader (mh.Name, mh.Namespace, mh.Actor); 652 if (x >= 0) 653 msg.Headers.RemoveAt (x); 654 msg.Headers.Add ((MessageHeader) mh); 655 } 656 msg.Properties.CopyProperties (context.OutgoingMessageProperties); 657 } 658 659 // FIXME: disabling MessageId as it's not seen for bug #567672 case. But might be required for PeerDuplexChannel. Check it later. 660 //if (OutputSession != null) 661 // msg.Headers.MessageId = new UniqueId (OutputSession.Id); 662 msg.Properties.AllowOutputBatching = AllowOutputBatching; 663 664 if (msg.Version.Addressing.Equals (AddressingVersion.WSAddressing10)) { 665 if (msg.Headers.MessageId == null) 666 msg.Headers.MessageId = new UniqueId (); 667 if (msg.Headers.ReplyTo == null) 668 msg.Headers.ReplyTo = new EndpointAddress (Constants.WsaAnonymousUri); 669 if (msg.Headers.To == null && RemoteAddress != null) 670 msg.Headers.To = RemoteAddress.Uri; 671 } 672 673 return msg; 674 } 675 676 #endregion 677 } 678 } 679