1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //------------------------------------------------------------
5 namespace System.ServiceModel.Channels
7 using System.Diagnostics;
10 using System.ServiceModel.Diagnostics;
12 using System.ServiceModel.Diagnostics.Application;
14 class PacketRoutableHeader : DictionaryHeader
16 PacketRoutableHeader()
21 public static void AddHeadersTo(Message message, MessageHeader header)
23 int index = message.Headers.FindHeader(DotNetOneWayStrings.HeaderName, DotNetOneWayStrings.Namespace);
28 header = PacketRoutableHeader.Create();
30 message.Headers.Add(header);
34 public static void ValidateMessage(Message message)
36 if (!TryValidateMessage(message))
38 throw TraceUtility.ThrowHelperError(
39 new ProtocolException(SR.GetString(SR.OneWayHeaderNotFound)), message);
43 public static bool TryValidateMessage(Message message)
45 int index = message.Headers.FindHeader(
46 DotNetOneWayStrings.HeaderName, DotNetOneWayStrings.Namespace);
51 public static PacketRoutableHeader Create()
53 return new PacketRoutableHeader();
56 public override XmlDictionaryString DictionaryName
58 get { return XD.DotNetOneWayDictionary.HeaderName; }
61 public override XmlDictionaryString DictionaryNamespace
63 get { return XD.DotNetOneWayDictionary.Namespace; }
66 protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
68 // no contents necessary
73 /// OneWayChannelFactory built on top of IRequestChannel
75 class RequestOneWayChannelFactory : LayeredChannelFactory<IOutputChannel>
77 PacketRoutableHeader packetRoutableHeader;
79 public RequestOneWayChannelFactory(OneWayBindingElement bindingElement, BindingContext context)
80 : base(context.Binding, context.BuildInnerChannelFactory<IRequestChannel>())
82 if (bindingElement.PacketRoutable)
84 this.packetRoutableHeader = PacketRoutableHeader.Create();
88 protected override IOutputChannel OnCreateChannel(EndpointAddress to, Uri via)
90 IRequestChannel innerChannel =
91 ((IChannelFactory<IRequestChannel>)this.InnerChannelFactory).CreateChannel(to, via);
93 return new RequestOutputChannel(this, innerChannel, this.packetRoutableHeader);
96 class RequestOutputChannel : OutputChannel
98 IRequestChannel innerChannel;
99 MessageHeader packetRoutableHeader;
101 public RequestOutputChannel(ChannelManagerBase factory,
102 IRequestChannel innerChannel, MessageHeader packetRoutableHeader)
105 this.innerChannel = innerChannel;
106 this.packetRoutableHeader = packetRoutableHeader;
109 #region Inner Channel delegation
110 public override EndpointAddress RemoteAddress
112 get { return this.innerChannel.RemoteAddress; }
115 public override Uri Via
117 get { return this.innerChannel.Via; }
120 protected override void OnAbort()
122 this.innerChannel.Abort();
125 protected override void OnOpen(TimeSpan timeout)
127 this.innerChannel.Open(timeout);
130 protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
132 return this.innerChannel.BeginOpen(timeout, callback, state);
135 protected override void OnEndOpen(IAsyncResult result)
137 this.innerChannel.EndOpen(result);
140 protected override void OnClose(TimeSpan timeout)
142 this.innerChannel.Close(timeout);
145 protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
147 return this.innerChannel.BeginClose(timeout, callback, state);
150 protected override void OnEndClose(IAsyncResult result)
152 this.innerChannel.EndClose(result);
155 public override T GetProperty<T>()
157 T result = base.GetProperty<T>();
161 result = this.innerChannel.GetProperty<T>();
168 // add our oneWay header to every message (if it's not already there)
169 protected override void AddHeadersTo(Message message)
171 base.AddHeadersTo(message);
173 if (this.packetRoutableHeader != null)
175 PacketRoutableHeader.AddHeadersTo(message, this.packetRoutableHeader);
179 protected override void OnSend(Message message, TimeSpan timeout)
181 Message response = this.innerChannel.Request(message, timeout);
184 ValidateResponse(response);
188 protected override IAsyncResult OnBeginSend(Message message, TimeSpan timeout, AsyncCallback callback, object state)
190 return this.innerChannel.BeginRequest(message, timeout, callback, state);
193 protected override void OnEndSend(IAsyncResult result)
195 Message response = this.innerChannel.EndRequest(result);
198 ValidateResponse(response);
202 void ValidateResponse(Message response)
204 if (response != null)
206 if (response.Version == MessageVersion.None && response is NullMessage)
212 Exception innerException = null;
214 if (response.IsFault)
218 MessageFault messageFault = MessageFault.CreateFault(response, TransportDefaults.MaxFaultSize);
219 innerException = new FaultException(messageFault);
228 if (e is CommunicationException ||
229 e is TimeoutException ||
233 innerException = e; // expected exception generating fault
242 throw TraceUtility.ThrowHelperError(
243 new ProtocolException(SR.GetString(SR.OneWayUnexpectedResponse), innerException),
251 // OneWayChannelFactory built on top of IDuplexChannel
253 class DuplexOneWayChannelFactory : LayeredChannelFactory<IOutputChannel>
255 IChannelFactory<IDuplexChannel> innnerFactory;
258 public DuplexOneWayChannelFactory(OneWayBindingElement bindingElement, BindingContext context)
259 : base(context.Binding, context.BuildInnerChannelFactory<IDuplexChannel>())
261 this.innnerFactory = (IChannelFactory<IDuplexChannel>)this.InnerChannelFactory;
262 this.packetRoutable = bindingElement.PacketRoutable;
265 protected override IOutputChannel OnCreateChannel(EndpointAddress address, Uri via)
267 IDuplexChannel channel = this.innnerFactory.CreateChannel(address, via);
268 return new DuplexOutputChannel(this, channel);
271 class DuplexOutputChannel : OutputChannel
273 IDuplexChannel innerChannel;
276 public DuplexOutputChannel(DuplexOneWayChannelFactory factory, IDuplexChannel innerChannel)
279 this.packetRoutable = factory.packetRoutable;
280 this.innerChannel = innerChannel;
283 public override EndpointAddress RemoteAddress
285 get { return this.innerChannel.RemoteAddress; }
288 public override Uri Via
290 get { return this.innerChannel.Via; }
293 protected override void OnAbort()
295 this.innerChannel.Abort();
298 protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
300 return this.innerChannel.BeginClose(timeout, callback, state);
303 protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
305 return this.innerChannel.BeginOpen(timeout, callback, state);
308 protected override IAsyncResult OnBeginSend(Message message, TimeSpan timeout, AsyncCallback callback, object state)
310 StampMessage(message);
311 return this.innerChannel.BeginSend(message, timeout, callback, state);
314 protected override void OnClose(TimeSpan timeout)
316 this.innerChannel.Close(timeout);
319 protected override void OnEndClose(IAsyncResult result)
321 this.innerChannel.EndClose(result);
324 protected override void OnEndOpen(IAsyncResult result)
326 this.innerChannel.EndOpen(result);
329 protected override void OnEndSend(IAsyncResult result)
331 this.innerChannel.EndSend(result);
334 protected override void OnOpen(TimeSpan timeout)
336 this.innerChannel.Open(timeout);
339 protected override void OnSend(Message message, TimeSpan timeout)
341 StampMessage(message);
342 this.innerChannel.Send(message, timeout);
345 void StampMessage(Message message)
347 if (this.packetRoutable)
349 PacketRoutableHeader.AddHeadersTo(message, null);
356 /// OneWayChannelFactory built on top of IDuplexSessionChannel
358 class DuplexSessionOneWayChannelFactory : LayeredChannelFactory<IOutputChannel>
360 ChannelPool<IDuplexSessionChannel> channelPool;
361 ChannelPoolSettings channelPoolSettings;
364 public DuplexSessionOneWayChannelFactory(OneWayBindingElement bindingElement, BindingContext context)
365 : base(context.Binding, context.BuildInnerChannelFactory<IDuplexSessionChannel>())
367 this.packetRoutable = bindingElement.PacketRoutable;
369 ISecurityCapabilities innerSecurityCapabilities = this.InnerChannelFactory.GetProperty<ISecurityCapabilities>();
371 // can't pool across outer channels if the inner channels support client auth
372 if (innerSecurityCapabilities != null && innerSecurityCapabilities.SupportsClientAuthentication)
374 this.channelPoolSettings = bindingElement.ChannelPoolSettings.Clone();
378 this.channelPool = new ChannelPool<IDuplexSessionChannel>(bindingElement.ChannelPoolSettings);
382 internal ChannelPool<IDuplexSessionChannel> GetChannelPool(out bool cleanupChannelPool)
384 if (this.channelPool != null)
386 cleanupChannelPool = false;
387 return this.channelPool;
391 cleanupChannelPool = true;
392 Fx.Assert(this.channelPoolSettings != null, "Need either settings or a pool");
393 return new ChannelPool<IDuplexSessionChannel>(this.channelPoolSettings);
397 protected override void OnAbort()
399 if (this.channelPool != null)
401 this.channelPool.Close(TimeSpan.Zero);
406 protected override void OnClose(TimeSpan timeout)
408 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
409 if (this.channelPool != null)
411 this.channelPool.Close(timeoutHelper.RemainingTime());
413 base.OnClose(timeoutHelper.RemainingTime());
416 protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
418 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
419 if (this.channelPool != null)
421 this.channelPool.Close(timeoutHelper.RemainingTime());
423 return base.OnBeginClose(timeoutHelper.RemainingTime(), callback, state);
426 protected override IOutputChannel OnCreateChannel(EndpointAddress address, Uri via)
428 return new DuplexSessionOutputChannel(this, address, via);
431 class DuplexSessionOutputChannel : OutputChannel
433 ChannelPool<IDuplexSessionChannel> channelPool;
434 EndpointAddress remoteAddress;
435 IChannelFactory<IDuplexSessionChannel> innerFactory;
436 AsyncCallback onReceive;
438 bool cleanupChannelPool;
441 public DuplexSessionOutputChannel(DuplexSessionOneWayChannelFactory factory,
442 EndpointAddress remoteAddress, Uri via)
445 this.channelPool = factory.GetChannelPool(out cleanupChannelPool);
446 this.packetRoutable = factory.packetRoutable;
447 this.innerFactory = (IChannelFactory<IDuplexSessionChannel>)factory.InnerChannelFactory;
448 this.remoteAddress = remoteAddress;
452 public override EndpointAddress RemoteAddress
454 get { return this.remoteAddress; }
457 public override Uri Via
459 get { return this.via; }
462 #region Channel Lifetime
463 protected override void OnOpen(TimeSpan timeout)
467 protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
469 return new CompletedAsyncResult(callback, state);
472 protected override void OnEndOpen(IAsyncResult result)
474 CompletedAsyncResult.End(result);
477 protected override void OnAbort()
479 if (cleanupChannelPool)
481 this.channelPool.Close(TimeSpan.Zero);
485 protected override void OnClose(TimeSpan timeout)
487 if (cleanupChannelPool)
489 this.channelPool.Close(timeout);
493 protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
495 if (cleanupChannelPool)
497 this.channelPool.Close(timeout);
499 return new CompletedAsyncResult(callback, state);
502 protected override void OnEndClose(IAsyncResult result)
504 CompletedAsyncResult.End(result);
508 protected override IAsyncResult OnBeginSend(Message message, TimeSpan timeout, AsyncCallback callback, object state)
510 return new SendAsyncResult(this, message, timeout, callback, state);
513 protected override void OnEndSend(IAsyncResult result)
515 SendAsyncResult.End(result);
518 protected override void OnSend(Message message, TimeSpan timeout)
520 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
521 ChannelPoolKey key = null;
522 bool isConnectionFromPool = true;
523 IDuplexSessionChannel innerChannel =
524 GetChannelFromPool(ref timeoutHelper, out key, out isConnectionFromPool);
526 bool success = false;
529 if (!isConnectionFromPool)
531 StampInitialMessage(message);
532 innerChannel.Open(timeoutHelper.RemainingTime());
533 StartBackgroundReceive(innerChannel);
536 innerChannel.Send(message, timeoutHelper.RemainingTime());
543 CleanupChannel(innerChannel, false, key, isConnectionFromPool, ref timeoutHelper);
547 CleanupChannel(innerChannel, true, key, isConnectionFromPool, ref timeoutHelper);
550 // kick off an async receive so that we notice when the server is trying to shutdown
551 void StartBackgroundReceive(IDuplexSessionChannel channel)
553 if (this.onReceive == null)
555 this.onReceive = Fx.ThunkCallback(new AsyncCallback(OnReceive));
558 channel.BeginReceive(TimeSpan.MaxValue, this.onReceive, channel);
561 void OnReceive(IAsyncResult result)
563 IDuplexSessionChannel channel = (IDuplexSessionChannel)result.AsyncState;
564 bool success = false;
567 Message message = channel.EndReceive(result);
570 channel.Close(this.channelPool.IdleTimeout);
578 catch (CommunicationException e)
580 DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
582 catch (TimeoutException e)
584 if (TD.CloseTimeoutIsEnabled())
586 TD.CloseTimeout(e.Message);
588 DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
599 void StampInitialMessage(Message message)
601 if (this.packetRoutable)
603 PacketRoutableHeader.AddHeadersTo(message, null);
607 void CleanupChannel(IDuplexSessionChannel channel, bool connectionStillGood, ChannelPoolKey key, bool isConnectionFromPool, ref TimeoutHelper timeoutHelper)
609 if (isConnectionFromPool)
611 this.channelPool.ReturnConnection(key, channel, connectionStillGood, timeoutHelper.RemainingTime());
615 if (connectionStillGood)
617 this.channelPool.AddConnection(key, channel, timeoutHelper.RemainingTime());
626 IDuplexSessionChannel GetChannelFromPool(ref TimeoutHelper timeoutHelper, out ChannelPoolKey key,
627 out bool isConnectionFromPool)
629 isConnectionFromPool = true;
632 IDuplexSessionChannel pooledChannel
633 = this.channelPool.TakeConnection(this.RemoteAddress, this.Via, timeoutHelper.RemainingTime(), out key);
635 if (pooledChannel == null)
637 isConnectionFromPool = false;
638 return this.innerFactory.CreateChannel(RemoteAddress, Via);
641 // only return good connections
642 if (pooledChannel.State == CommunicationState.Opened)
644 return pooledChannel;
647 // Abort stale connections from the pool
648 this.channelPool.ReturnConnection(key, pooledChannel, false, timeoutHelper.RemainingTime());
652 class SendAsyncResult : AsyncResult
654 DuplexSessionOutputChannel parent;
655 IDuplexSessionChannel innerChannel;
657 TimeoutHelper timeoutHelper;
658 static AsyncCallback onOpen;
659 static AsyncCallback onInnerSend = Fx.ThunkCallback(new AsyncCallback(OnInnerSend));
661 bool isConnectionFromPool;
663 public SendAsyncResult(DuplexSessionOutputChannel parent, Message message, TimeSpan timeout,
664 AsyncCallback callback, object state)
665 : base(callback, state)
667 this.parent = parent;
668 this.message = message;
669 this.timeoutHelper = new TimeoutHelper(timeout);
671 parent.GetChannelFromPool(ref this.timeoutHelper, out this.key, out this.isConnectionFromPool);
673 bool success = false;
674 bool completeSelf = true;
677 if (!this.isConnectionFromPool)
679 completeSelf = OpenNewChannel();
684 completeSelf = SendMessage();
703 public static void End(IAsyncResult result)
705 AsyncResult.End<SendAsyncResult>(result);
708 void Cleanup(bool connectionStillGood)
710 parent.CleanupChannel(this.innerChannel, connectionStillGood, this.key,
711 this.isConnectionFromPool, ref this.timeoutHelper);
714 bool OpenNewChannel()
718 onOpen = Fx.ThunkCallback(new AsyncCallback(OnOpen));
721 this.parent.StampInitialMessage(this.message);
722 IAsyncResult result = this.innerChannel.BeginOpen(timeoutHelper.RemainingTime(), onOpen, this);
723 if (!result.CompletedSynchronously)
728 this.CompleteOpen(result);
732 void CompleteOpen(IAsyncResult result)
734 this.innerChannel.EndOpen(result);
735 this.parent.StartBackgroundReceive(this.innerChannel);
740 IAsyncResult result = innerChannel.BeginSend(this.message, onInnerSend, this);
741 if (!result.CompletedSynchronously)
746 innerChannel.EndSend(result);
750 static void OnOpen(IAsyncResult result)
752 if (result.CompletedSynchronously)
757 SendAsyncResult thisPtr = (SendAsyncResult)result.AsyncState;
759 Exception completionException = null;
760 bool completeSelf = false;
763 thisPtr.CompleteOpen(result);
764 completeSelf = thisPtr.SendMessage();
766 #pragma warning suppress 56500 // [....], transferring exception to another thread
775 completionException = e;
780 thisPtr.Cleanup(completionException == null);
781 thisPtr.Complete(false, completionException);
785 static void OnInnerSend(IAsyncResult result)
787 if (result.CompletedSynchronously)
792 SendAsyncResult thisPtr = (SendAsyncResult)result.AsyncState;
794 Exception completionException = null;
797 thisPtr.innerChannel.EndSend(result);
799 #pragma warning suppress 56500 // [....], transferring exception to another thread
807 completionException = e;
810 thisPtr.Cleanup(completionException == null);
811 thisPtr.Complete(false, completionException);