//---------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------- namespace System.ServiceModel.Discovery { using System; using System.Collections.ObjectModel; using System.ServiceModel.Channels; using System.Runtime; using System.ServiceModel.Dispatcher; class OnlineAnnouncementChannelDispatcher : ChannelDispatcherBase { [Fx.Tag.SynchronizationObject()] object thisLock; Collection announcementEndpoints; Collection publishedEndpoints; int dispatchersToWait; AnnouncementDispatcherAsyncResult announceOnlineAsyncResult; DiscoveryMessageSequenceGenerator discoveryMessageSequenceGenerator; ServiceHostBase serviceHostBase; TimeoutHelper asyncOpenTimeoutHelper; internal OnlineAnnouncementChannelDispatcher(ServiceHostBase serviceHostBase, Collection announcementEndpoints, Collection publishedEndpoints, DiscoveryMessageSequenceGenerator discoveryMessageSequenceGenerator) { Fx.Assert(serviceHostBase != null, "The serviceHostBase must be non null."); Fx.Assert(announcementEndpoints != null && announcementEndpoints.Count > 0, "The Announcement Endpoints collection must be non null and not empty."); Fx.Assert(publishedEndpoints != null, "The Published Endpoints collection must be non null."); Fx.Assert(discoveryMessageSequenceGenerator != null, "The discoveryMessageSequenceGenerator must be non null."); this.serviceHostBase = serviceHostBase; this.announcementEndpoints = announcementEndpoints; this.publishedEndpoints = publishedEndpoints; this.discoveryMessageSequenceGenerator = discoveryMessageSequenceGenerator; this.thisLock = new object(); InitChannelDispatchers(serviceHostBase); } public override ServiceHostBase Host { get { return this.serviceHostBase; } } public override IChannelListener Listener { get { return null; } } protected override TimeSpan DefaultCloseTimeout { get { return TimeSpan.FromMinutes(1); } } protected override TimeSpan DefaultOpenTimeout { get { return TimeSpan.FromMinutes(1); } } void OnChannelDispatcherOpened(object sender, EventArgs e) { bool startAnnouncements = false; lock (this.thisLock) { if ((--this.dispatchersToWait) == 0) { if (this.announceOnlineAsyncResult != null) { startAnnouncements = true; this.dispatchersToWait--; } } } if (startAnnouncements) { this.announceOnlineAsyncResult.Start(this.asyncOpenTimeoutHelper.RemainingTime(), false); } } void InitChannelDispatchers(ServiceHostBase serviceHostBase) { this.dispatchersToWait = serviceHostBase.ChannelDispatchers.Count; EventHandler handler = new EventHandler(OnChannelDispatcherOpened); foreach (ChannelDispatcherBase channelDispatcher in serviceHostBase.ChannelDispatchers) { channelDispatcher.Opened += handler; } } protected override void OnAbort() { if (this.announceOnlineAsyncResult != null) { this.announceOnlineAsyncResult.Cancel(); } } protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state) { bool startAnnouncements = false; this.asyncOpenTimeoutHelper = new TimeoutHelper(timeout); this.asyncOpenTimeoutHelper.RemainingTime(); this.announceOnlineAsyncResult = new AnnouncementDispatcherAsyncResult(this.announcementEndpoints, this.publishedEndpoints, this.discoveryMessageSequenceGenerator, true, callback, state); lock (this.thisLock) { if (this.dispatchersToWait == 0) { startAnnouncements = true; this.dispatchersToWait--; } } if (this.State != CommunicationState.Opening) { // Fixes the ---- when OnAbort is called after OnBeginOpen but before this.announceOnlineAsyncResult is created this.announceOnlineAsyncResult.Cancel(); } else if (startAnnouncements) { this.announceOnlineAsyncResult.Start(this.asyncOpenTimeoutHelper.RemainingTime(), true); } return this.announceOnlineAsyncResult; } protected override void OnEndOpen(IAsyncResult result) { AnnouncementDispatcherAsyncResult.End(result); } protected override void OnOpen(TimeSpan timeout) { this.announceOnlineAsyncResult = new AnnouncementDispatcherAsyncResult(this.announcementEndpoints, this.publishedEndpoints, this.discoveryMessageSequenceGenerator, true, null, null); if (this.State != CommunicationState.Opening) { // Fixes the ---- when OnAbort is called after OnOpen but before this.announceOnlineAsyncResult is created this.announceOnlineAsyncResult.Cancel(); } else { this.announceOnlineAsyncResult.Start(timeout, true); } AnnouncementDispatcherAsyncResult.End(this.announceOnlineAsyncResult); } protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state) { return new CompletedAsyncResult(callback, state); } protected override void OnEndClose(IAsyncResult result) { CompletedAsyncResult.End(result); } protected override void OnClose(TimeSpan timeout) { } } }