title: WCF right solution for Publish/subscribe pattern implementation
body: <p>I implemented my own code of Publish/subscribe pattern implementation with WCF with WSDualHttpBinding, but i've a little problem with timeouts that i explain later, for now let me show what i'm doing:</p>
  
  <pre><code>public interface IEventSubscriber
  {
      [OperationContract]
      void NotifyEvent(EventNotification notification);
      [OperationContract]
      void NotifyServiceDisconnecting();
  }
  
  [ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IEventSubscriber))]
  public interface IEventPublisherService
  {
      [OperationContract(IsOneWay = false, IsInitiating = true)]
      void Subscribe(string culture);
      [OperationContract(IsOneWay = false, IsInitiating = false, IsTerminating = true)]
      void Unsubscribe();
  }
  
  [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
  internal class EventPublisherServiceImpl : IEventPublisherService
  {
      ServiceHost host;
      public bool StartService()
      {
          bool ret = false;
          try
          {
              Uri baseAddress = new Uri(ConfigurationManager.AppSettings[GlobalConstants.CfgKeyConfigEventPublishserServiceBaseAddress].ToString());
              EventHelper.AddEvent(string.Format("Event Publisher Service on: {0}", baseAddress.ToString()));
  
              host = new ServiceHost(this, baseAddress);
  
              // duplex session enable http binding
              WSDualHttpBinding httpBinding = new WSDualHttpBinding(WSDualHttpSecurityMode.None);
              httpBinding.ReceiveTimeout = TimeSpan.FromMinutes(10);
              httpBinding.ReliableSession = new ReliableSession();
              httpBinding.ReliableSession.Ordered = true;
              httpBinding.ReliableSession.InactivityTimeout = TimeSpan.FromMinutes(10);
              host.AddServiceEndpoint(typeof(IEventPublisherService), httpBinding, baseAddress);
  
              // Enable metadata publishing.
              ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
              smb.HttpGetEnabled = true;
              smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
              host.Description.Behaviors.Add(smb);
  
              // Open the ServiceHost to start listening for messages.
              host.Open();
              ret = true;
          }
          catch (Exception e)
          {
              EventHelper.AddException(e.Message);
          }
  
          return ret;
      }
   ...
  
  }
  </code></pre>
  
  <p>now in my implementation class i have a list of subscribers that are stored in memory, when a new notification arrived the following code is performed for each subscriber:</p>
  
  <pre><code> ...
      /// &lt;summary&gt;
      /// List of active subscribers
      /// &lt;/summary&gt;
      private static Dictionary&lt;IEventSubscriber, string&gt; subscribers = new Dictionary&lt;IEventSubscriber, string&gt;();
  
   ...
  </code></pre>
  
  <p>that i use it like this:</p>
  
  <pre><code>    internal void Subscribe(string culture)
      {
          lock (subscribers)
          {
              // Get callback contract as specified on the service definition
              IEventSubscriber callback = OperationContext.Current.GetCallbackChannel&lt;IEventSubscriber&gt;();
  
              // Add subscriber to the list of active subscribers
              if (!subscribers.ContainsKey(callback))
              {
                  subscribers.Add(callback, culture);
              }
          }
      }
  
   ...
  
      private void OnNotificationEvent(NormalEvent notification)
      {
          lock (subscribers)
          {
              List&lt;IEventSubscriber&gt; listToRemove = new List&lt;IEventSubscriber&gt;();
              //  Method signature: Parallel.ForEach(IEnumerable&lt;TSource&gt; source, Action&lt;TSource&gt; body)
              Parallel.ForEach(subscribers, kvp =&gt;
              {
                  try
                  {
                      kvp.Key.NotifyEvent(new EventNotification(notification, kvp.Value));
                  }
                  catch (Exception ex)
                  {
                      EventHelper.AddException(string.Format("Error notifying event notification to client: {0} - removing this one", ex.Message));
                      listToRemove.Add(kvp.Key);
                  }
  
              } //close lambda expression
              ); //close method invocation
  
              Parallel.ForEach(listToRemove, subs =&gt;
              {
                  try
                  {
                      subs.NotifyServiceDisconnecting();
                  }
                  catch (Exception ex) {
                      EventHelper.AddException(string.Format("Failed to notify client that is to be removed: {0}", 
                          ex.Message));
                  }
                  subscribers.Remove(subs);
              }
              );
          }
      }
  </code></pre>
  
  <p>What is the problem with this, when timeouts are achieved (note that i set 10 minutes for ReceiveTimeout and inactive timeout) the subscribers that are in the list go to fault state, and the following exception is catched in the <strong>OnNotificationEvent</strong> </p>
  
  <p>*<em>The operation 'NotifyEvent' could not be completed because the sessionful channel timed out waiting to receive a message.  To increase the timeout, either set the receiveTimeout property on the binding in your configuration file, or set the ReceiveTimeout property on the Binding directly. *</em></p>
  
  <p>Ok i can increase the timeout value, but if i do this it will happen some time, eventually.</p>
  
  <p>My question are: i'm doing something wrong when trying to implement this pattern? or exists any other way of implementing this pattern a better way that avoid this problem? or exist any way of reconnecting the faulted callback channel (for what i'm reading it's not possible, but due to that i can't notify the client that is connection was lost, letting the client blind not knowing that the communication ended!? or is a way to give knowledge that he lost communication with the publisher!?)</p>
  
  <p>Of course solution like ping messages are out of date :) but ok, if nothing better appears look like i've to implement something like that...</p>
  
  <p>Thanks </p>